Skip to content

Commit

Permalink
implement integration as a separate crate
Browse files Browse the repository at this point in the history
Signed-off-by: tison <[email protected]>
  • Loading branch information
tisonkun committed Oct 11, 2024
1 parent 309cc8d commit 02facb3
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 2 deletions.
3 changes: 2 additions & 1 deletion sqlx-jiff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ postgres = ["sqlx/postgres"]

[dependencies]
jiff = { path = ".." }
sqlx = { version = "0.8.2" }
serde = { version = "1.0" }
sqlx = { version = "0.8" }
34 changes: 33 additions & 1 deletion sqlx-jiff/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,34 @@
use std::ops::{Deref, DerefMut};
use serde::{Deserialize, Serialize};

#[cfg(feature = "postgres")]
mod postgres;
mod postgres;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Timestamp(pub jiff::Timestamp);

impl From<Timestamp> for jiff::Timestamp {
fn from(ts: Timestamp) -> Self {
ts.0
}
}

impl From<jiff::Timestamp> for Timestamp {
fn from(ts: jiff::Timestamp) -> Self {
Self(ts)
}
}

impl Deref for Timestamp {
type Target = jiff::Timestamp;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Timestamp {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
62 changes: 62 additions & 0 deletions sqlx-jiff/src/postgres.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::str::FromStr;
use sqlx::{Database, Decode, Encode, Postgres, Type};
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat};
use sqlx::postgres::types::Oid;
use jiff::SignedDuration;
use crate::Timestamp;

impl Type<Postgres> for Timestamp {
fn type_info() -> PgTypeInfo {
// 1184 => PgType::Timestamptz
PgTypeInfo::with_oid(Oid(1184))
}
}

impl PgHasArrayType for Timestamp {
fn array_type_info() -> PgTypeInfo {
// 1185 => PgType::TimestamptzArray
PgTypeInfo::with_oid(Oid(1185))
}
}

impl Encode<'_, Postgres> for Timestamp {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
// TIMESTAMP is encoded as the microseconds since the epoch
let micros = self
.0
.duration_since(postgres_epoch_timestamp())
.as_micros();
let micros = i64::try_from(micros)
.map_err(|_| format!("Timestamp {} out of range for Postgres: {micros}", self.0))?;
Encode::<Postgres>::encode(micros, buf)
}

fn size_hint(&self) -> usize {
size_of::<i64>()
}
}

impl<'r> Decode<'r, Postgres> for Timestamp {
fn decode(value: <Postgres as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
Ok(match value.format() {
PgValueFormat::Binary => {
// TIMESTAMP is encoded as the microseconds since the epoch
let us = Decode::<Postgres>::decode(value)?;
let ts = postgres_epoch_timestamp().checked_add(SignedDuration::from_micros(us))?;
Timestamp(ts)
}
PgValueFormat::Text => {
let s = value.as_str()?;
let ts = jiff::Timestamp::from_str(s)?;
Timestamp(ts)
}
})
}
}

fn postgres_epoch_timestamp() -> jiff::Timestamp {
jiff::Timestamp::from_str("2000-01-01T00:00:00Z")
.expect("2000-01-01T00:00:00Z is a valid timestamp")
}

0 comments on commit 02facb3

Please sign in to comment.