console-table-printer icon indicating copy to clipboard operation
console-table-printer copied to clipboard

feat: Teach Table to render top grouping headers

Open nulltoken opened this issue 3 months ago β€’ 15 comments

πŸ‘€What is this pr about?

Partially fix #472.

Reuses the internal rendering mechanism to leverage existing features and benefit from existing test coverage.

Implementation favored a design which is as less invasive as possible with regards to the current code.

Pending topics:

Potential future features:

πŸš€ Changes

Added

  • [x] New Table option: groupedColumnsHeaders

πŸ–Ό Screenshots

const table = new Table({
  groupedColumnsHeaders: [
    { name: 'G1', width: 9 }
]});

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚                          G1                          β”‚
    β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { name: 'G1', width: 2 },
    { name: 'G2', width: 2 },
    { name: 'G3', width: 5 },
]});

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   G1    β”‚      G2      β”‚             G3              β”‚
    β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { kind: 'PLACEHOLDER', width: 1 },
    { name: 'G1', width: 2 },
    { name: 'G2', width: 2 },
    { name: 'G3', width: 4 },
]});

         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚   G1    β”‚      G2      β”‚           G3           β”‚
    β”Œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { name: 'G1', width: 2 },
    { name: 'G2', width: 2 },
    { name: 'G3', width: 4 },
]});

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   G1    β”‚      G2      β”‚        G3         β”‚
    β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { name: 'G1', width: 2 },
    { name: 'G2', width: 2 },
    { kind: 'PLACEHOLDER', width: 1 },
    { name: 'G3', width: 4 },
]});

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   G1    β”‚      G2      β”‚    β”‚           G3           β”‚
    β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { kind: 'PLACEHOLDER', width: 1 },
    { name: 'G1', width: 2 },
    { kind: 'PLACEHOLDER', width: 1 },
    { name: 'G2', width: 2 },
    { name: 'G3', width: 2 },
]});

         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚   G1    β”‚         β”‚   G2    β”‚   G3    β”‚
    β”Œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { kind: 'PLACEHOLDER', width: 5 },
    { name: 'G1', width: 2 },
]});

                                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                  β”‚   G1    β”‚
    β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { kind: 'PLACEHOLDER', width: 7 },
    { name: 'VERY LONG GROUP NAME', width: 2 },
]});

                                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                            β”‚  VERY LONG   β”‚
    β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

---
const table = new Table({
  groupedColumnsHeaders: [
    { name: 'LEFT', alignment: 'left', width: 2 },
    { name: 'RIGHT', alignment: 'right', width: 2 },
]});

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                                                     
    β”‚ LEFT    β”‚        RIGHT β”‚                            
    β”œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  A β”‚  B β”‚  C β”‚       D β”‚  E β”‚  F β”‚  G β”‚  H β”‚       I β”‚
    β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ A1 β”‚ B1 β”‚ C1 β”‚      D1 β”‚ E1 β”‚ F1 β”‚ G1 β”‚ H1 β”‚ I 00001 β”‚
    β”‚ A2 β”‚ B2 β”‚ C2 β”‚ D 00002 β”‚ E2 β”‚ F2 β”‚ G2 β”‚ H2 β”‚      I2 β”‚
    β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

nulltoken avatar Oct 07 '25 21:10 nulltoken

Codecov Report

:x: Patch coverage is 96.96970% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/internalTable/grouped-column-headers.ts 96.75% 1 Missing and 4 partials :warning:

:loudspeaker: Thoughts on this report? Let us know!

codecov[bot] avatar Oct 07 '25 21:10 codecov[bot]

@ayonious Thoughts?

nulltoken avatar Oct 07 '25 21:10 nulltoken

I will take some time to review this. Maybe around a week. But the feature looks good.

ayonious avatar Oct 08 '25 08:10 ayonious

I would also suggest to add more tests like test/features/groupedColumnHeaders

ayonious avatar Oct 08 '25 09:10 ayonious

I would also suggest to add more tests like test/features/groupedColumnHeaders

@ayonious Will do.

Although I'm not sure what is the proper balance between what's expected to live under test/features/groupedColumnHeaders/render.tests vs test/render.tests.

Will push something and let you decide ;-)

nulltoken avatar Oct 08 '25 11:10 nulltoken

Will push something and let you decide ;-)

Done.

Moved everything under test/features/ and added one global rendering test in test/render.tests.ts

nulltoken avatar Oct 08 '25 21:10 nulltoken

@ayonious rebased

nulltoken avatar Oct 20 '25 22:10 nulltoken

Im thinking about some special cases

  1. with calculated columns
  2. With columns that are far from each other but belongs to same parent column
  3. group of groups

And with this solution, column headers need to be in same order as the other columns, means columns actually have to have a strict serial.

So although this is a nice partial solution its complication makes it hard for me to allow this in the package.

If there is something simpler and more effective I can take a look. Lets first maybe brainstorm and see if we can come up with something simpler.

ayonious avatar Oct 21 '25 17:10 ayonious

Lets first maybe brainstorm and see if we can come up with something simpler.

That's the simplest I've been able to come with. How would you approach it?

nulltoken avatar Oct 21 '25 17:10 nulltoken

Instead of grouping serially with widths, I think its more correct grouping them with the ids.

groupedColumnsHeaders: [{
   childIds: 'col1', 'col2'
   id: 'title1'
   title: 'Title1'
}]

ayonious avatar Oct 30 '25 13:10 ayonious

@ayonious Thanks for the feedback. Let me see what I can come up with.

nulltoken avatar Oct 30 '25 21:10 nulltoken

@ayonious Thanks for the feedback. Let me see what I can come up with.

@ayonious Here's a new version exposing a column name based aggregation definition.

Thoughts?

nulltoken avatar Oct 30 '25 22:10 nulltoken

Note: In order to make your review easier, I've pushed my changes in a fixup commit.

nulltoken avatar Oct 30 '25 22:10 nulltoken

my changes in a fixup commit

@ayonious Thoughts?

nulltoken avatar Nov 10 '25 18:11 nulltoken

@ayonious Here's a new version exposing a column name based aggregation definition.

@ayonious Have you had the time to take a look at the proposal yet?

nulltoken avatar Nov 21 '25 20:11 nulltoken

@ayonious Kind bump?

nulltoken avatar Dec 11 '25 19:12 nulltoken