|
| 1 | +use bytes::BytesMut; |
| 2 | +use jiff_02::{ |
| 3 | + civil::{Date,DateTime,Time}, |
| 4 | +Span,SpanRound,Timestamp,Unit, |
| 5 | +}; |
| 6 | +use postgres_protocol::types; |
| 7 | +use std::error::Error; |
| 8 | + |
| 9 | +usecrate::{FromSql,IsNull,ToSql,Type}; |
| 10 | + |
| 11 | +constfnbase() ->DateTime{ |
| 12 | +DateTime::constant(2000,1,1,0,0,0,0) |
| 13 | +} |
| 14 | + |
| 15 | +/// The number of seconds from the Unix epoch to 2000-01-01 00:00:00 UTC. |
| 16 | +constPG_EPOCH:i64 =946684800; |
| 17 | + |
| 18 | +fnbase_ts() ->Timestamp{ |
| 19 | +Timestamp::new(PG_EPOCH,0).unwrap() |
| 20 | +} |
| 21 | + |
| 22 | +fnround_us<'a>() ->SpanRound<'a>{ |
| 23 | +SpanRound::new().largest(Unit::Microsecond) |
| 24 | +} |
| 25 | + |
| 26 | +fndecode_err<E>(_e:E) ->Box<dynError +Sync +Send> |
| 27 | +where |
| 28 | +E:Error, |
| 29 | +{ |
| 30 | +"value too large to decode".into() |
| 31 | +} |
| 32 | + |
| 33 | +fntransmit_err<E>(_e:E) ->Box<dynError +Sync +Send> |
| 34 | +where |
| 35 | +E:Error, |
| 36 | +{ |
| 37 | +"value too large to transmit".into() |
| 38 | +} |
| 39 | + |
| 40 | +impl<'a>FromSql<'a>forDateTime{ |
| 41 | +fnfrom_sql(_:&Type,raw:&[u8]) ->Result<DateTime,Box<dynError +Sync +Send>>{ |
| 42 | +let v = types::timestamp_from_sql(raw)?; |
| 43 | +Span::new() |
| 44 | +.try_microseconds(v) |
| 45 | +.and_then(|s|base().checked_add(s)) |
| 46 | +.map_err(decode_err) |
| 47 | +} |
| 48 | + |
| 49 | +accepts!(TIMESTAMP); |
| 50 | +} |
| 51 | + |
| 52 | +implToSqlforDateTime{ |
| 53 | +fnto_sql(&self, _:&Type,w:&mutBytesMut) ->Result<IsNull,Box<dynError +Sync +Send>>{ |
| 54 | +let v =self |
| 55 | +.since(base()) |
| 56 | +.and_then(|s| s.round(round_us())) |
| 57 | +.map_err(transmit_err)? |
| 58 | +.get_microseconds(); |
| 59 | + types::timestamp_to_sql(v, w); |
| 60 | +Ok(IsNull::No) |
| 61 | +} |
| 62 | + |
| 63 | +accepts!(TIMESTAMP); |
| 64 | +to_sql_checked!(); |
| 65 | +} |
| 66 | + |
| 67 | +impl<'a>FromSql<'a>forTimestamp{ |
| 68 | +fnfrom_sql(_:&Type,raw:&[u8]) ->Result<Timestamp,Box<dynError +Sync +Send>>{ |
| 69 | +let v = types::timestamp_from_sql(raw)?; |
| 70 | +Span::new() |
| 71 | +.try_microseconds(v) |
| 72 | +.and_then(|s|base_ts().checked_add(s)) |
| 73 | +.map_err(decode_err) |
| 74 | +} |
| 75 | + |
| 76 | +accepts!(TIMESTAMPTZ); |
| 77 | +} |
| 78 | + |
| 79 | +implToSqlforTimestamp{ |
| 80 | +fnto_sql(&self, _:&Type,w:&mutBytesMut) ->Result<IsNull,Box<dynError +Sync +Send>>{ |
| 81 | +let v =self |
| 82 | +.since(base_ts()) |
| 83 | +.and_then(|s| s.round(round_us())) |
| 84 | +.map_err(transmit_err)? |
| 85 | +.get_microseconds(); |
| 86 | + types::timestamp_to_sql(v, w); |
| 87 | +Ok(IsNull::No) |
| 88 | +} |
| 89 | + |
| 90 | +accepts!(TIMESTAMPTZ); |
| 91 | +to_sql_checked!(); |
| 92 | +} |
| 93 | + |
| 94 | +impl<'a>FromSql<'a>forDate{ |
| 95 | +fnfrom_sql(_:&Type,raw:&[u8]) ->Result<Date,Box<dynError +Sync +Send>>{ |
| 96 | +let v = types::date_from_sql(raw)?; |
| 97 | +Span::new() |
| 98 | +.try_days(v) |
| 99 | +.and_then(|s|base().date().checked_add(s)) |
| 100 | +.map_err(decode_err) |
| 101 | +} |
| 102 | +accepts!(DATE); |
| 103 | +} |
| 104 | + |
| 105 | +implToSqlforDate{ |
| 106 | +fnto_sql(&self, _:&Type,w:&mutBytesMut) ->Result<IsNull,Box<dynError +Sync +Send>>{ |
| 107 | +let v =self.since(base().date()).map_err(transmit_err)?.get_days(); |
| 108 | + types::date_to_sql(v, w); |
| 109 | +Ok(IsNull::No) |
| 110 | +} |
| 111 | + |
| 112 | +accepts!(DATE); |
| 113 | +to_sql_checked!(); |
| 114 | +} |
| 115 | + |
| 116 | +impl<'a>FromSql<'a>forTime{ |
| 117 | +fnfrom_sql(_:&Type,raw:&[u8]) ->Result<Time,Box<dynError +Sync +Send>>{ |
| 118 | +let v = types::time_from_sql(raw)?; |
| 119 | +Span::new() |
| 120 | +.try_microseconds(v) |
| 121 | +.and_then(|s|Time::midnight().checked_add(s)) |
| 122 | +.map_err(decode_err) |
| 123 | +} |
| 124 | + |
| 125 | +accepts!(TIME); |
| 126 | +} |
| 127 | + |
| 128 | +implToSqlforTime{ |
| 129 | +fnto_sql(&self, _:&Type,w:&mutBytesMut) ->Result<IsNull,Box<dynError +Sync +Send>>{ |
| 130 | +let v =self |
| 131 | +.since(Time::midnight()) |
| 132 | +.and_then(|s| s.round(round_us())) |
| 133 | +.map_err(transmit_err)? |
| 134 | +.get_microseconds(); |
| 135 | + types::time_to_sql(v, w); |
| 136 | +Ok(IsNull::No) |
| 137 | +} |
| 138 | + |
| 139 | +accepts!(TIME); |
| 140 | +to_sql_checked!(); |
| 141 | +} |