use faucet_core::FaucetError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageKind {
Begin,
Commit,
Origin,
Relation,
Type,
Insert,
Update,
Delete,
Truncate,
}
impl MessageKind {
pub fn from_byte(b: u8) -> Result<Self, FaucetError> {
Ok(match b {
b'B' => Self::Begin,
b'C' => Self::Commit,
b'O' => Self::Origin,
b'R' => Self::Relation,
b'Y' => Self::Type,
b'I' => Self::Insert,
b'U' => Self::Update,
b'D' => Self::Delete,
b'T' => Self::Truncate,
other => {
return Err(FaucetError::Source(format!(
"pgoutput: unknown message kind {:?} (0x{other:02X})",
other as char
)));
}
})
}
pub fn as_byte(&self) -> u8 {
match self {
Self::Begin => b'B',
Self::Commit => b'C',
Self::Origin => b'O',
Self::Relation => b'R',
Self::Type => b'Y',
Self::Insert => b'I',
Self::Update => b'U',
Self::Delete => b'D',
Self::Truncate => b'T',
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReplicaIdentity {
Default,
Nothing,
Full,
Index,
}
impl ReplicaIdentity {
pub fn from_byte(b: u8) -> Result<Self, FaucetError> {
Ok(match b {
b'd' => Self::Default,
b'n' => Self::Nothing,
b'f' => Self::Full,
b'i' => Self::Index,
other => {
return Err(FaucetError::Source(format!(
"pgoutput: unknown replica identity {:?} (0x{other:02X})",
other as char
)));
}
})
}
pub fn as_byte(&self) -> u8 {
match self {
Self::Default => b'd',
Self::Nothing => b'n',
Self::Full => b'f',
Self::Index => b'i',
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColumnDesc {
pub flags: u8,
pub name: String,
pub type_oid: u32,
pub type_modifier: i32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Begin {
pub final_lsn: u64,
pub commit_ts: i64, pub xid: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Commit {
pub flags: u8,
pub commit_lsn: u64,
pub end_lsn: u64,
pub commit_ts: i64, }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Relation {
pub oid: u32,
pub namespace: String,
pub name: String,
pub replica_identity: ReplicaIdentity,
pub columns: Vec<ColumnDesc>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TupleCell {
Null,
UnchangedToast,
Text(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TupleData {
pub cells: Vec<TupleCell>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Insert {
pub relation_oid: u32,
pub new: TupleData,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateOldKind {
None,
Key,
Full,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Update {
pub relation_oid: u32,
pub old_kind: UpdateOldKind,
pub old: Option<TupleData>,
pub new: TupleData,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeleteOldKind {
Key,
Full,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Delete {
pub relation_oid: u32,
pub old_kind: DeleteOldKind,
pub old: TupleData,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Truncate {
pub relation_oids: Vec<u32>,
pub cascade: bool,
pub restart_identity: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Message {
Begin(Begin),
Commit(Commit),
Origin,
Relation(Relation),
Type,
Insert(Insert),
Update(Update),
Delete(Delete),
Truncate(Truncate),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn message_kind_byte_round_trip() {
for byte in [b'B', b'C', b'O', b'R', b'Y', b'I', b'U', b'D', b'T'] {
let kind = MessageKind::from_byte(byte).expect("known kind");
assert_eq!(kind.as_byte(), byte);
}
}
#[test]
fn message_kind_unknown_byte_errors() {
assert!(MessageKind::from_byte(b'Z').is_err());
}
#[test]
fn relation_replica_identity_round_trip() {
for byte in [b'd', b'n', b'f', b'i'] {
let id = ReplicaIdentity::from_byte(byte).expect("known");
assert_eq!(id.as_byte(), byte);
}
assert!(ReplicaIdentity::from_byte(b'x').is_err());
}
}