Spreadsheet-UX op een echte relationele engine

main

Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.

2.0 kB Ruw bestand
import { isNumericColumn } from './format.js';
import type { AggFn, ColumnMeta } from './types.js';

/**
 * Which summaries a column can honestly carry.
 *
 * Type decides, as it does everywhere else here: a text column has no total,
 * and a checkbox has no average worth showing. Offering only what the type
 * supports means the footer never holds a function the database would have to
 * refuse — the same bargain the cell editors make.
 *
 * A link column summarises by the label the grid shows, not by the row id it
 * stores, so counting the filled ones counts the rows that point somewhere.
 */
export function aggsFor(col: ColumnMeta): AggFn[] {
  if (col.type === 'checkbox') return ['checked', 'empty'];
  if (isNumericColumn(col)) return ['sum', 'avg', 'min', 'max', 'filled', 'empty'];
  if (col.type === 'date') return ['min', 'max', 'filled', 'empty'];
  return ['filled', 'empty', 'unique'];
}

export function isAggAllowed(col: ColumnMeta, fn: AggFn): boolean {
  return aggsFor(col).includes(fn);
}

/**
 * Whether the result is in the column's own units.
 *
 * A sum of a currency column is money and formats like the cells above it; a
 * count of the filled ones is a number of rows and must not pick up a currency
 * sign it has no business wearing.
 */
export function aggKeepsUnits(fn: AggFn): boolean {
  return fn === 'sum' || fn === 'avg' || fn === 'min' || fn === 'max';
}

/** What the menu and the footer call the function, given the column it is on. */
export function aggLabel(fn: AggFn, col?: ColumnMeta): string {
  if (col?.type === 'date') {
    if (fn === 'min') return 'Earliest';
    if (fn === 'max') return 'Latest';
  }
  if (col?.type === 'checkbox' && fn === 'empty') return 'Unchecked';
  switch (fn) {
    case 'sum':
      return 'Sum';
    case 'avg':
      return 'Average';
    case 'min':
      return 'Min';
    case 'max':
      return 'Max';
    case 'filled':
      return 'Filled';
    case 'empty':
      return 'Empty';
    case 'unique':
      return 'Unique';
    case 'checked':
      return 'Checked';
  }
}