use crate::bridge::envelope::PhysicalPlan;
use crate::control::server::response_shape::compose::{ShapeOutcome, shape_response_materialized};
use crate::control::server::response_shape::schema::OutputSchema;
use crate::control::server::response_shape::types::PlanKind;
use crate::control::state::SharedState;
use nodedb_types::{DatabaseId, NodeDbError, TenantId};
pub(super) enum HttpShaped {
Rows(Vec<serde_json::Value>),
Passthrough,
}
pub(super) fn shape_http_payload(
payload: &[u8],
plan: &PhysicalPlan,
plan_kind: PlanKind,
projection: Option<&OutputSchema>,
state: &SharedState,
database_id: DatabaseId,
tenant_id: TenantId,
) -> Result<HttpShaped, NodeDbError> {
match shape_response_materialized(
payload,
plan,
plan_kind,
projection,
state,
database_id,
tenant_id,
)? {
ShapeOutcome::Rows(shaped) => Ok(HttpShaped::Rows(
shaped
.rows
.into_iter()
.map(serde_json::Value::Object)
.collect(),
)),
ShapeOutcome::Passthrough => Ok(HttpShaped::Passthrough),
}
}
pub(super) fn passthrough_json_row(payload: &[u8]) -> serde_json::Value {
if let Ok(val) = nodedb_types::json_from_msgpack(payload) {
return val;
}
if let Ok(val) = sonic_rs::from_slice::<serde_json::Value>(payload) {
return val;
}
use base64::Engine;
let encoded = base64::engine::general_purpose::STANDARD.encode(payload);
serde_json::json!({ "data": encoded })
}
pub(super) fn passthrough_to_ndjson(payload: &[u8], ndjson: &mut String) {
let json_str = crate::data::executor::response_codec::decode_payload_to_json(payload);
if json_str.trim_start().starts_with('[') {
for lv in sonic_rs::to_array_iter(json_str.as_str()).flatten() {
ndjson.push_str(lv.as_raw_str());
ndjson.push('\n');
}
} else {
ndjson.push_str(&json_str);
ndjson.push('\n');
}
}
pub(super) fn ddl_results_to_json(
results: Vec<crate::control::server::shared::ddl::DdlResult>,
) -> Vec<serde_json::Value> {
use crate::control::server::shared::ddl::DdlResult;
let mut rows = Vec::new();
for result in results {
match result {
DdlResult::Status { command, .. } => {
rows.push(serde_json::json!({
"type": "execution",
"tag": command,
}));
}
DdlResult::Rows(shaped) => {
for row in shaped.rows {
rows.push(serde_json::Value::Object(row));
}
}
DdlResult::Empty => {
rows.push(serde_json::json!({ "type": "empty" }));
}
}
}
rows
}