Apply projection to a binary msgpack row, keeping only requested columns. Projection names may be unqualified ("name") while keys are qualified ("users.name"). Returns a new msgpack map with only matching fields, using the unqualified name as the output key.
(
row: &[u8],
projection: &[nodedb_physical::physical_plan::JoinProjection],
)
| 220 | /// ("users.name"). Returns a new msgpack map with only matching fields, |
| 221 | /// using the unqualified name as the output key. |
| 222 | pub(super) fn binary_row_project( |
| 223 | row: &[u8], |
| 224 | projection: &[nodedb_physical::physical_plan::JoinProjection], |
| 225 | ) -> Vec<u8> { |
| 226 | let Some((count, pos)) = msgpack_scan::map_header(row, 0) else { |
| 227 | return row.to_vec(); |
| 228 | }; |
| 229 | |
| 230 | // First pass: find matching entries. |
| 231 | struct Entry { |
| 232 | output_key: String, |
| 233 | val_start: usize, |
| 234 | val_end: usize, |
| 235 | } |
| 236 | let mut entries = Vec::with_capacity(projection.len()); |
| 237 | let mut scan_pos = pos; |
| 238 | for _ in 0..count { |
| 239 | let key = msgpack_scan::read_str(row, scan_pos); |
| 240 | scan_pos = match msgpack_scan::skip_value(row, scan_pos) { |
| 241 | Some(p) => p, |
| 242 | None => break, |
| 243 | }; |
| 244 | let val_start = scan_pos; |
| 245 | scan_pos = match msgpack_scan::skip_value(row, scan_pos) { |
| 246 | Some(p) => p, |
| 247 | None => break, |
| 248 | }; |
| 249 | if let Some(k) = &key { |
| 250 | let short = k.rsplit('.').next().unwrap_or(k); |
| 251 | if let Some(projected) = projection |
| 252 | .iter() |
| 253 | .find(|p| p.source == short || p.source == *k) |
| 254 | { |
| 255 | entries.push(Entry { |
| 256 | output_key: projected.output.clone(), |
| 257 | val_start, |
| 258 | val_end: scan_pos, |
| 259 | }); |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | // Build output map. |
| 265 | let mut buf = Vec::with_capacity(row.len()); |
| 266 | write_map_header(&mut buf, entries.len()); |
| 267 | for e in &entries { |
| 268 | write_str(&mut buf, &e.output_key); |
| 269 | buf.extend_from_slice(&row[e.val_start..e.val_end]); |
| 270 | } |
| 271 | buf |
| 272 | } |
| 273 | |
| 274 | #[cfg(test)] |
| 275 | mod tests { |