use bytes::Bytes;
use bytes::{BufMut, BytesMut};
use std::convert::TryFrom;
use std::num::TryFromIntError;
use thiserror::Error;
use crate::constants::{PgErrorCodes, PgErrorLevels};
use crate::engine::objects::SqlTuple;
#[derive(Clone, Debug)]
pub struct NetworkFrame {
pub message_type: u8,
pub payload: Bytes,
}
impl NetworkFrame {
pub fn new(message_type: u8, payload: Bytes) -> NetworkFrame {
NetworkFrame {
message_type,
payload,
}
}
pub fn authentication_ok() -> NetworkFrame {
NetworkFrame::new(b'R', Bytes::from_static(b"\0\0\0\0"))
}
pub fn command_complete(command_tag: String) -> NetworkFrame {
let mut buffer = BytesMut::new();
buffer.put(command_tag.as_bytes());
buffer.put_u8(b'\0');
NetworkFrame::new(b'C', buffer.freeze())
}
pub fn data_rows(rows: Vec<SqlTuple>) -> Result<Vec<NetworkFrame>, NetworkFrameError> {
let mut frames = vec![];
for row in rows {
let mut buffer = BytesMut::new();
let column_count = u16::try_from(row.0.len())?;
buffer.put_u16(column_count);
for field in row.0.into_iter() {
match field {
Some(f) => {
let f_str = format!("{}", f);
let f_bytes = f_str.as_bytes();
let f_len = i32::try_from(f_bytes.len())?;
buffer.put_i32(f_len);
buffer.put(f_bytes);
}
None => {
buffer.put_i32(-1);
}
}
}
frames.push(NetworkFrame::new(b'D', buffer.freeze()));
}
Ok(frames)
}
pub fn ready_for_query() -> NetworkFrame {
NetworkFrame::new(b'Z', Bytes::from_static(b"I"))
}
pub fn row_description(column_names: Vec<String>) -> Result<NetworkFrame, NetworkFrameError> {
let mut buffer = BytesMut::new();
let field_count = u16::try_from(column_names.len())?;
buffer.put_u16(field_count);
for column in column_names {
buffer.put(column.as_bytes());
buffer.put_u8(b'\0');
buffer.put_u32(0); buffer.put_u16(0); buffer.put_u32(0); buffer.put_i16(0); buffer.put_i32(0); buffer.put_i16(0); }
Ok(NetworkFrame::new(b'T', buffer.freeze()))
}
pub fn error_response(
severity: PgErrorLevels,
code: PgErrorCodes,
message: String,
) -> NetworkFrame {
let mut buffer = BytesMut::new();
buffer.put_u8(b'S'); buffer.put(severity.value());
buffer.put_u8(b'\0');
buffer.put_u8(b'M'); buffer.put(message.as_bytes());
buffer.put_u8(b'\0');
buffer.put_u8(b'C'); buffer.put(code.value());
buffer.put_u8(b'\0');
buffer.put_u8(b'\0');
NetworkFrame::new(b'E', buffer.freeze())
}
}
#[derive(Error, Debug)]
pub enum NetworkFrameError {
#[error(transparent)]
TooManyFields(#[from] TryFromIntError),
}