(
rows: &mut [(String, serde_json::Value)],
indices: &[usize],
spec: &WindowFuncSpec,
)
| 67 | } |
| 68 | |
| 69 | pub(super) fn apply_ntile( |
| 70 | rows: &mut [(String, serde_json::Value)], |
| 71 | indices: &[usize], |
| 72 | spec: &WindowFuncSpec, |
| 73 | ) { |
| 74 | let n = spec |
| 75 | .args |
| 76 | .first() |
| 77 | .and_then(|e| { |
| 78 | if let SqlExpr::Literal(v) = e { |
| 79 | v.as_f64().map(|x| x as usize) |
| 80 | } else { |
| 81 | None |
| 82 | } |
| 83 | }) |
| 84 | .unwrap_or(1) |
| 85 | .max(1); |
| 86 | let total = indices.len(); |
| 87 | if total == 0 { |
| 88 | return; |
| 89 | } |
| 90 | for (pos, &i) in indices.iter().enumerate() { |
| 91 | // Integer division distributes rows as evenly as possible (PostgreSQL semantics). |
| 92 | let bucket = (pos * n / total) + 1; |
| 93 | set_window_col(&mut rows[i].1, &spec.alias, serde_json::json!(bucket)); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /// PostgreSQL `percent_rank()` — `(rank - 1) / (partition_rows - 1)`. Single- |
| 98 | /// row partitions return 0. Peer rows share their leader's value. |
no test coverage detected