use super::AlterConfig;
use crate::error::{Error, Result};
use crate::proto::{PbAddColumn, PbDropColumn, PbModifyColumn, PbRenameColumn};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColumnPositionType {
Last,
}
impl ColumnPositionType {
pub fn to_i32(self) -> i32 {
match self {
Self::Last => 0,
}
}
pub fn try_from_i32(value: i32) -> Result<Self> {
match value {
0 => Ok(Self::Last),
_ => Err(Error::IllegalArgument {
message: format!("Unsupported ColumnPositionType: {value}"),
}),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AddColumn {
pub column_name: String,
pub data_type_json: Vec<u8>,
pub comment: Option<String>,
pub position: ColumnPositionType,
}
impl AddColumn {
pub fn to_pb(&self) -> PbAddColumn {
PbAddColumn {
column_name: self.column_name.clone(),
data_type_json: self.data_type_json.clone(),
comment: self.comment.clone(),
column_position_type: self.position.to_i32(),
agg_function_type: None,
agg_function_params: Vec::new(),
}
}
pub fn from_pb(pb: &PbAddColumn) -> Result<Self> {
Ok(Self {
column_name: pb.column_name.clone(),
data_type_json: pb.data_type_json.clone(),
comment: pb.comment.clone(),
position: ColumnPositionType::try_from_i32(pb.column_position_type)?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DropColumn {
pub column_name: String,
}
impl DropColumn {
pub fn to_pb(&self) -> PbDropColumn {
PbDropColumn {
column_name: self.column_name.clone(),
}
}
pub fn from_pb(pb: &PbDropColumn) -> Self {
Self {
column_name: pb.column_name.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RenameColumn {
pub old_column_name: String,
pub new_column_name: String,
}
impl RenameColumn {
pub fn to_pb(&self) -> PbRenameColumn {
PbRenameColumn {
old_column_name: self.old_column_name.clone(),
new_column_name: self.new_column_name.clone(),
}
}
pub fn from_pb(pb: &PbRenameColumn) -> Self {
Self {
old_column_name: pb.old_column_name.clone(),
new_column_name: pb.new_column_name.clone(),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct AlterTableChanges {
pub config_changes: Vec<AlterConfig>,
pub add_columns: Vec<AddColumn>,
pub drop_columns: Vec<DropColumn>,
pub rename_columns: Vec<RenameColumn>,
pub modify_columns: Vec<ModifyColumn>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ModifyColumn {
pub column_name: String,
pub data_type_json: Option<Vec<u8>>,
pub comment: Option<String>,
pub position: Option<ColumnPositionType>,
}
impl ModifyColumn {
pub fn to_pb(&self) -> PbModifyColumn {
PbModifyColumn {
column_name: self.column_name.clone(),
data_type_json: self.data_type_json.clone(),
comment: self.comment.clone(),
column_position_type: self.position.map(|p| p.to_i32()),
}
}
pub fn from_pb(pb: &PbModifyColumn) -> Result<Self> {
Ok(Self {
column_name: pb.column_name.clone(),
data_type_json: pb.data_type_json.clone(),
comment: pb.comment.clone(),
position: pb
.column_position_type
.map(ColumnPositionType::try_from_i32)
.transpose()?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_column_position_type_roundtrip() {
assert_eq!(
ColumnPositionType::try_from_i32(ColumnPositionType::Last.to_i32()).unwrap(),
ColumnPositionType::Last
);
assert!(ColumnPositionType::try_from_i32(1).is_err());
assert!(ColumnPositionType::try_from_i32(3).is_err());
}
#[test]
fn test_add_column_pb_roundtrip() {
let original = AddColumn {
column_name: "amount".to_string(),
data_type_json: b"{\"type\":\"BIGINT\"}".to_vec(),
comment: Some("the amount".to_string()),
position: ColumnPositionType::Last,
};
let pb = original.to_pb();
assert_eq!(AddColumn::from_pb(&pb).unwrap(), original);
}
#[test]
fn test_drop_column_pb_roundtrip() {
let original = DropColumn {
column_name: "obsolete".to_string(),
};
let pb = original.to_pb();
assert_eq!(DropColumn::from_pb(&pb), original);
}
#[test]
fn test_rename_column_pb_roundtrip() {
let original = RenameColumn {
old_column_name: "old_name".to_string(),
new_column_name: "new_name".to_string(),
};
let pb = original.to_pb();
assert_eq!(RenameColumn::from_pb(&pb), original);
}
#[test]
fn test_modify_column_pb_roundtrip_full() {
let original = ModifyColumn {
column_name: "x".to_string(),
data_type_json: Some(b"{\"type\":\"DOUBLE\"}".to_vec()),
comment: Some("changed".to_string()),
position: Some(ColumnPositionType::Last),
};
let pb = original.to_pb();
assert_eq!(ModifyColumn::from_pb(&pb).unwrap(), original);
}
#[test]
fn test_modify_column_pb_roundtrip_empty() {
let original = ModifyColumn {
column_name: "x".to_string(),
data_type_json: None,
comment: None,
position: None,
};
let pb = original.to_pb();
assert_eq!(ModifyColumn::from_pb(&pb).unwrap(), original);
}
}