use crate::row_json::{column_to_json, column_to_json_v2};
use cufflink_types::db::{Column, DbError, DbResponse, RowMap};
use serde_json::Value;
use tokio_postgres::Row;
pub fn legacy_rows(rows: &[Row]) -> Vec<Value> {
rows.iter()
.map(|row| {
Value::Object(
row.columns()
.iter()
.enumerate()
.map(|(i, column)| {
(
column.name().to_string(),
column_to_json(row, i, column.type_()),
)
})
.collect(),
)
})
.collect()
}
pub fn rows_v2(columns: &[tokio_postgres::Column], rows: &[Row]) -> Result<DbResponse, DbError> {
let rows = rows
.iter()
.map(|row| {
columns
.iter()
.enumerate()
.map(|(i, column)| {
column_to_json_v2(row, i, column.type_())
.map(|value| (column.name().to_string(), value))
})
.collect::<Result<RowMap, DbError>>()
})
.collect::<Result<Vec<_>, _>>()?;
Ok(DbResponse::Rows {
rows,
columns: columns_v2(columns),
})
}
pub struct ColumnOrder(Vec<(String, usize)>);
impl ColumnOrder {
pub fn of(columns: &[tokio_postgres::Column]) -> Self {
let last: std::collections::BTreeMap<&str, usize> = columns
.iter()
.enumerate()
.map(|(i, column)| (column.name(), i))
.collect();
Self(
last.into_iter()
.map(|(name, i)| (Value::from(name).to_string(), i))
.collect(),
)
}
pub fn legacy_row(&self, row: &Row, out: &mut String) {
self.write(out, |i| column_to_json(row, i, row.columns()[i].type_()));
}
pub fn row_v2(&self, row: &Row, out: &mut String) -> Result<(), DbError> {
let mut values = row
.columns()
.iter()
.enumerate()
.map(|(i, column)| column_to_json_v2(row, i, column.type_()).map(Some))
.collect::<Result<Vec<Option<Value>>, DbError>>()?;
self.write(out, |i| values[i].take().unwrap_or(Value::Null));
Ok(())
}
fn write(&self, out: &mut String, mut value: impl FnMut(usize) -> Value) {
out.push('{');
for (n, (key, i)) in self.0.iter().enumerate() {
if n > 0 {
out.push(',');
}
out.push_str(key);
out.push(':');
out.push_str(&value(*i).to_string());
}
out.push('}');
}
}
pub fn columns_v2(columns: &[tokio_postgres::Column]) -> Vec<Column> {
columns
.iter()
.map(|column| Column {
name: column.name().to_string(),
type_name: column.type_().name().to_string(),
})
.collect()
}