// Copyright (c) 2023-2025 ParadeDB, Inc. // // This file is part of ParadeDB - Postgres for Search and Analytics // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use cursive_core::align::HAlign; use cursive_table_view::TableViewItem; use postgres::types::{FromSql, Type}; use postgres::Row; use std::cmp::Ordering; use std::error::Error; use std::fmt::{Display, Formatter}; /// A row wrapper so we can display query results in a cursive_table_view. #[derive(Clone)] pub struct ArbitraryTableRow(pub Row); impl TableViewItem for ArbitraryTableRow { fn to_column(&self, column: usize) -> String { get_str_value(&self.0, column) } /// We won't worry about sorting; always return `Ordering::Greater`. fn cmp(&self, _other: &Self, _column: usize) -> Ordering where Self: Sized, { Ordering::Greater } } #[allow(clippy::if_same_then_else)] impl ArbitraryTableRow { pub fn halign(&self, i: usize) -> HAlign { if self.0.try_get::<_, String>(i).is_ok() { HAlign::Left } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Right } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Right } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Right } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Right } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Left } else if self .0 .try_get::<_, Option>(i) .is_ok() { HAlign::Right } else if self.0.try_get::<_, Option>>(i).is_ok() { HAlign::Left } else if self.0.try_get::<_, Option>(i).is_ok() { HAlign::Right } else { HAlign::Left } } pub fn col_width(&self, i: usize) -> Option { if self.0.try_get::<_, String>(i).is_ok() { None } else if self.0.try_get::<_, Option>(i).is_ok() { Some(10) } else if self.0.try_get::<_, Option>(i).is_ok() { Some(10) } else if self.0.try_get::<_, Option>(i).is_ok() { Some(10) } else if self.0.try_get::<_, Option>(i).is_ok() { Some(10) } else if self.0.try_get::<_, Option>(i).is_ok() { Some(5) } else if self .0 .try_get::<_, Option>(i) .is_ok() { Some(10) } else if self.0.try_get::<_, Option>>(i).is_ok() { None } else if self.0.try_get::<_, Option>(i).is_ok() { Some(10) } else { None } } } fn get_str_value(row: &Row, i: usize) -> String { // Attempt some common types if let Ok(v) = row.try_get::<_, Option>(i) { v.unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { // for NUMERIC support v.map(|x| x.to_string()).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>>(i) { v.map(|x| format!("{x:?}")).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>>(i) { v.map(|x| format!("{x:?}")).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>>(i) { v.map(|x| format!("{x:?}")).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>>(i) { v.map(|x| format!("{x:?}")).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>>(i) { v.map(|x| format!("{x:?}")).unwrap_or_default() } else if let Ok(v) = row.try_get::<_, Option>(i) { v.map(|x| format!("{x}")).unwrap_or_default() } else if row.columns()[i].type_().name() == "void" { "(void)".to_string() } else { format!("{}: type unknown", row.columns()[i].type_().name()) } } #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] #[repr(transparent)] struct Xid(u32); impl Display for Xid { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl<'a> FromSql<'a> for Xid { fn from_sql(_ty: &Type, raw: &'a [u8]) -> Result> { let xid = u32::from_be_bytes(raw.try_into()?); Ok(Xid(xid)) } fn accepts(ty: &Type) -> bool { ty.name() == "xid" } }