use crate::core::bindings::{
SqlHostState,
codec_utils,
generated::wasm_sql::core::{
codecs::{PushResult, ValuePosition},
query::QueryResults,
query_types::SqlArguments,
util_types::Error,
},
};
use crate::postgres::bindings::generated::wasm_sql::postgres::codecs::{
Date, Hstore, Inet, IpAddr, Macaddr, Numeric, PgInterval, Time, Timestamp, Timestamptz, Uuid,
};
use bigdecimal::BigDecimal;
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use ipnet::IpNet;
use mac_address::MacAddress;
use sqlx::postgres::types::PgInterval as SqlxPgInterval;
use sqlx::types::JsonRawValue;
use sqlx::{postgres::types::PgHstore, types::Json};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
impl crate::postgres::bindings::generated::wasm_sql::postgres::codecs::Host for SqlHostState {
fn push_int16(
&mut self,
value: Option<i16>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_int16(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<i16>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_int32(
&mut self,
value: Option<i32>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_int32(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<i32>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_int64(
&mut self,
value: Option<i64>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_int64(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<i64>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_float32(
&mut self,
value: Option<f32>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_float32(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<f32>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_float64(
&mut self,
value: Option<f64>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_float64(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<f64>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_string(
&mut self,
value: Option<wasmtime::component::__internal::String>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_string(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<wasmtime::component::__internal::String>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_bool(
&mut self,
value: Option<bool>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_bool(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<bool>, Error> {
codec_utils::decode(self.table.get(&result)?, position)
}
fn push_json(
&mut self,
value: Option<wasmtime::component::__internal::String>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let to = self.table.get(&to)?;
match value {
Some(value) => {
let raw_value =
JsonRawValue::from_string(value).map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(Json(raw_value), to)
}
None => codec_utils::encode(None::<Json<Box<JsonRawValue>>>, to),
}
}
fn get_json(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<wasmtime::component::__internal::String>, Error> {
let a = codec_utils::decode::<Option<&JsonRawValue>>(self.table.get(&result)?, position)?;
Ok(a.map(|x| x.get().to_string()))
}
fn push_uuid(
&mut self,
value: Option<Uuid>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| sqlx::types::Uuid::try_parse(v.as_str()))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_uuid(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Uuid>, Error> {
let value: Option<sqlx::types::Uuid> =
codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.to_string()))
}
fn push_hstore(
&mut self,
value: Option<Hstore>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value.map(|v: Vec<(String, Option<String>)>| PgHstore(v.into_iter().collect()));
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_hstore(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Hstore>, Error> {
let value: Option<PgHstore> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.into_iter().collect()))
}
fn push_date(
&mut self,
value: Option<Date>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| NaiveDate::parse_from_str(&v, "%Y-%m-%d"))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_date(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Date>, Error> {
let value: Option<NaiveDate> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.format("%Y-%m-%d").to_string()))
}
fn push_time(
&mut self,
value: Option<Time>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| NaiveTime::parse_from_str(&v, "%H:%M:%S%.f"))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_time(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Time>, Error> {
let value: Option<NaiveTime> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.format("%H:%M:%S%.f").to_string()))
}
fn push_timestamp(
&mut self,
value: Option<Timestamp>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| NaiveDateTime::parse_from_str(&v, "%Y-%m-%dT%H:%M:%S%.f"))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_timestamp(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Timestamp>, Error> {
let value: Option<NaiveDateTime> =
codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.format("%Y-%m-%dT%H:%M:%S%.f").to_string()))
}
fn push_timestamptz(
&mut self,
value: Option<Timestamptz>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| DateTime::parse_from_rfc3339(&v).map(|dt| dt.with_timezone(&Utc)))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_timestamptz(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Timestamptz>, Error> {
let value: Option<DateTime<Utc>> =
codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.to_rfc3339()))
}
fn push_interval(
&mut self,
value: Option<PgInterval>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value.map(|v| SqlxPgInterval {
months: v.months,
days: v.days,
microseconds: v.microseconds,
});
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_interval(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<PgInterval>, Error> {
let value: Option<SqlxPgInterval> =
codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| PgInterval {
months: v.months,
days: v.days,
microseconds: v.microseconds,
}))
}
fn push_inet(
&mut self,
value: Option<Inet>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value: Option<IpNet> = value.as_ref().map(Into::into);
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_inet(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Inet>, Error> {
let value: Option<IpNet> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.as_ref().map(Into::into))
}
fn push_cidr(
&mut self,
value: Option<Inet>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value: Option<IpNet> = value.as_ref().map(Into::into);
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_cidr(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Inet>, Error> {
let value: Option<IpNet> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.as_ref().map(Into::into))
}
fn push_macaddr(
&mut self,
value: Option<Macaddr>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value.map(|v| MacAddress::new(v.into()));
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_macaddr(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Macaddr>, Error> {
let value: Option<MacAddress> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| {
let b = v.bytes();
(b[0], b[1], b[2], b[3], b[4], b[5])
}))
}
fn push_numeric(
&mut self,
value: Option<Numeric>,
to: wasmtime::component::Resource<SqlArguments>,
) -> PushResult {
let value = value
.map(|v| BigDecimal::from_str(&v))
.transpose()
.map_err(|e| Error::Encode(e.to_string()))?;
codec_utils::encode(value, self.table.get(&to)?)
}
fn get_numeric(
&mut self,
result: wasmtime::component::Resource<QueryResults>,
position: ValuePosition,
) -> Result<Option<Numeric>, Error> {
let value: Option<BigDecimal> = codec_utils::decode(self.table.get(&result)?, position)?;
Ok(value.map(|v| v.to_string()))
}
}
impl From<&Inet> for IpNet {
fn from(inet: &Inet) -> Self {
match &inet.addr {
IpAddr::V4(v4) => {
let addr = Ipv4Addr::new(v4.0, v4.1, v4.2, v4.3);
IpNet::V4(ipnet::Ipv4Net::new(addr, inet.prefix_len).unwrap_or_else(|_| {
ipnet::Ipv4Net::new(addr, 32).unwrap()
}))
}
IpAddr::V6(v6) => {
let addr = Ipv6Addr::new(v6.0, v6.1, v6.2, v6.3, v6.4, v6.5, v6.6, v6.7);
IpNet::V6(ipnet::Ipv6Net::new(addr, inet.prefix_len).unwrap_or_else(|_| {
ipnet::Ipv6Net::new(addr, 128).unwrap()
}))
}
}
}
}
impl From<&IpNet> for Inet {
fn from(ipnet: &IpNet) -> Self {
match ipnet {
IpNet::V4(v4) => {
let octets = v4.addr().octets();
Inet {
addr: IpAddr::V4((octets[0], octets[1], octets[2], octets[3])),
prefix_len: v4.prefix_len(),
}
}
IpNet::V6(v6) => {
let segments = v6.addr().segments();
Inet {
addr: IpAddr::V6((
segments[0],
segments[1],
segments[2],
segments[3],
segments[4],
segments[5],
segments[6],
segments[7],
)),
prefix_len: v6.prefix_len(),
}
}
}
}
}