EERP Suite

API Reference

Hooks

useTable

The main hook for interacting with a table.

const {
  table,
  columns,
  rows,
  total,
  hasMore,
  isLoading,
  isRowsLoading,
  selectOptions,
  filters,
  sorts,
  setFilters,
  setSorts,
  updateCell,
  updateColumn,
  addColumn,
  deleteColumn,
  addRow,
  deleteRow,
  loadMore,
  loadSelectOptions,
  createSelectOption,
  updateSelectOption,
  deleteSelectOption,
} = useTable({ tableId: string });

Parameters

NameTypeDescription
tableIdstringThe ID of the table to load

Return Values

NameTypeDescription
tableTable | nullTable metadata
columnsColumn[]Column definitions
rowsRow[]Row data
totalnumberTotal row count
hasMorebooleanWhether more rows can be loaded
isLoadingbooleanInitial loading state
isRowsLoadingbooleanLoading state for row fetching
selectOptionsMap<string, SelectOption[]>Options by column ID
filtersQueryFilter[]Active filters
sortsQuerySort[]Active sorts
setFilters(filters: QueryFilter[]) => voidUpdate filters
setSorts(sorts: QuerySort[]) => voidUpdate sorts
updateCell(rowId, columnId, value) => PromiseUpdate a cell
updateColumn(columnId, updates) => PromiseUpdate column metadata
addColumn(input) => Promise<Column>Add a new column
deleteColumn(columnId) => PromiseDelete a column
addRow(cells?) => Promise<Row>Add a new row
deleteRow(rowId) => PromiseDelete a row
loadMore() => PromiseLoad more rows (pagination)
loadSelectOptions(columnId) => PromiseLoad select options
createSelectOption(columnId, name, color?) => PromiseCreate option
updateSelectOption(optionId, updates) => PromiseUpdate option
deleteSelectOption(columnId, optionId) => PromiseDelete option

Components

DataTableProvider

Context provider that supplies the database adapter.

<DataTableProvider
  dbAdapter={adapter}
  workspaceId="my-workspace"
  fileAdapter={fileAdapter}  // Optional
>
  {children}
</DataTableProvider>

Props

NameTypeRequiredDescription
dbAdapterDatabaseAdapterYesDatabase adapter instance
workspaceIdstringYesWorkspace/tenant ID
fileAdapterFileStorageAdapterNoFile storage adapter
childrenReactNodeYesChild components

TableView

The main table component.

<TableView
  columns={columns}
  rows={rows}
  selectOptions={selectOptions}
  onCellChange={(rowId, columnId, value) => {}}
  onAddRow={() => {}}
  onDeleteRow={(rowId) => {}}
  onColumnResize={(columnId, width) => {}}
  onColumnAlignmentChange={(columnId, alignment) => {}}
  onAddProperty={(name, type) => {}}
  onCreateSelectOption={(columnId, name, color) => {}}
  onUpdateSelectOption={(optionId, updates) => {}}
  onDeleteSelectOption={(columnId, optionId) => {}}
  enableKeyboardNav={true}
  sorts={sorts}
  onSortChange={(sorts) => {}}
  selectedRows={selectedRows}
  onSelectionChange={(selection) => {}}
  isLoading={isLoading}
  hasMore={hasMore}
  onLoadMore={() => {}}
  className=""
  style={{}}
/>

Props

NameTypeRequiredDescription
columnsColumn[]YesColumn definitions
rowsRow[]YesRow data
selectOptionsMap<string, SelectOption[]>NoSelect options by column
onCellChange(rowId, colId, value) => voidYesCell change handler
onAddRow() => voidNoAdd row handler
onDeleteRow(rowId) => voidNoDelete row handler
onColumnResize(colId, width) => voidNoColumn resize handler
onColumnAlignmentChange(colId, alignment) => voidNoColumn alignment handler (left/center/right)
onAddProperty(name, type) => voidNoAdd column handler
enableKeyboardNavbooleanNoEnable arrow key / Tab / Enter cell navigation (default: true)
sortsQuerySort[]NoActive sorts
onSortChange(sorts) => voidNoSort change handler
selectedRowsSet<string>NoSelected row IDs
onSelectionChange(selection) => voidNoSelection handler
isLoadingbooleanNoLoading state
hasMorebooleanNoHas more rows
onLoadMore() => voidNoLoad more handler
classNamestringNoCustom CSS class
styleCSSPropertiesNoInline styles

FilterBar

Filter controls for the table.

<FilterBar
  columns={columns}
  filters={filters}
  selectOptions={selectOptions}
  onFiltersChange={(filters) => {}}
/>

Props

NameTypeRequiredDescription
columnsColumn[]YesColumn definitions
filtersQueryFilter[]YesActive filters
selectOptionsMap<string, SelectOption[]>NoFor select column filters
onFiltersChange(filters) => voidYesFilter change handler

Types

Column

interface Column {
  id: string;
  tableId: string;
  name: string;
  type: ColumnType;
  position: number;
  width: number;
  isPrimary: boolean;
  config?: Record<string, unknown>;
}

ColumnType

type ColumnType =
  | 'text'
  | 'number'
  | 'date'
  | 'boolean'
  | 'select'
  | 'multi_select'
  | 'url'
  | 'file'
  | 'formula'
  | 'relation'
  | 'rollup';

Row

interface Row {
  id: string;
  tableId: string;
  cells: Record<string, CellValue>;
}

CellValue

type CellValue =
  | string
  | number
  | boolean
  | string[]  // multi_select
  | null;

SelectOption

interface SelectOption {
  id: string;
  columnId: string;
  name: string;
  color?: string;
  position: number;
}

QueryFilter

interface QueryFilter {
  columnId: string;
  operator: FilterOperator;
  value: CellValue;
}

type FilterOperator =
  | 'equals'
  | 'notEquals'
  | 'contains'
  | 'notContains'
  | 'greaterThan'
  | 'lessThan'
  | 'isEmpty'
  | 'isNotEmpty';

QuerySort

interface QuerySort {
  columnId: string;
  direction: 'asc' | 'desc';
}

useViews

Hook for managing table views.

const {
  views,
  currentView,
  isLoading,
  error,
  createView,
  updateView,
  deleteView,
  reorderViews,
  setCurrentView,
  refresh,
} = useViews({ tableId: string });

Parameters

NameTypeDescription
tableIdstringThe ID of the table to manage views for

Return Values

NameTypeDescription
viewsView[]Array of all views for the table
currentViewView | nullThe currently selected view
isLoadingbooleanLoading state during initial fetch
errorError | nullError if view fetching failed
createView(input: Omit<CreateViewInput, 'tableId'>) => Promise<View>Create a new view
updateView(viewId: string, updates: UpdateViewInput) => Promise<View>Update an existing view
deleteView(viewId: string) => Promise<void>Delete a view
reorderViews(viewIds: string[]) => Promise<void>Reorder views by position
setCurrentView(viewId: string) => voidSet the current active view
refresh() => Promise<void>Manually refresh views from database

ViewSwitcher

Tab-based view switcher component for navigating between different views of a table.

<ViewSwitcher
  views={views}
  currentViewId={currentViewId}
  onViewChange={(viewId) => {}}
  onCreateView={(type) => {}}
  onDeleteView={(viewId) => {}}
  onRenameView={(viewId, name) => {}}
/>

Props

NameTypeRequiredDescription
viewsView[]YesArray of views to display
currentViewIdstring | nullYesID of the currently active view
onViewChange(viewId: string) => voidYesCallback when view is selected
onCreateView(type: ViewType) => voidYesCallback to create a new view
onDeleteView(viewId: string) => voidYesCallback to delete a view
onRenameView(viewId: string, name: string) => voidYesCallback to rename a view

BoardView

Kanban-style board view component for visualizing data grouped by a select column.

<BoardView
  columns={columns}
  rows={rows}
  selectOptions={selectOptions}
  config={boardConfig}
  onCellChange={(rowId, columnId, value) => {}}
  onAddRow={(initialCells) => {}}
  onDeleteRow={(rowId) => {}}
  onCardClick={(rowId) => {}}
  onCreateSelectOption={(columnId, name, color) => {}}
  onUpdateSelectOption={(optionId, updates) => {}}
  onDeleteSelectOption={(columnId, optionId) => {}}
  onUploadFile={(rowId, columnId, file) => {}}
  onDeleteFile={(rowId, columnId, fileId) => {}}
  readOnly={false}
  isLoading={false}
  className=""
  style={{}}
/>

Props

NameTypeRequiredDescription
columnsColumn[]YesColumn definitions
rowsRow[]YesRow data
selectOptionsMap<string, SelectOption[]>NoSelect options by column ID
configBoardViewConfigYesBoard view configuration
onCellChange(rowId, colId, value) => voidNoCell change handler (for drag-drop)
onAddRow(initialCells?) => voidNoAdd row handler with initial values
onDeleteRow(rowId) => voidNoDelete row handler
onCardClick(rowId) => voidNoCard click handler
onCreateSelectOption(columnId, name, color?) => PromiseNoCreate select option
onUpdateSelectOption(optionId, updates) => PromiseNoUpdate select option
onDeleteSelectOption(columnId, optionId) => PromiseNoDelete select option
onUploadFile(rowId, columnId, file) => PromiseNoFile upload handler
onDeleteFile(rowId, columnId, fileId) => PromiseNoFile delete handler
readOnlybooleanNoDisable editing and drag-drop
isLoadingbooleanNoShow loading overlay
classNamestringNoCustom CSS class
styleCSSPropertiesNoInline styles

CalendarView

Calendar view component for displaying rows with date values on a monthly calendar.

<CalendarView
  rows={rows}
  columns={columns}
  config={calendarConfig}
  onRowClick={(row) => {}}
  onDayClick={(date, events) => {}}
  onDateChange={(date) => {}}
  isLoading={false}
  className=""
  style={{}}
/>

Props

NameTypeRequiredDescription
rowsRow[]YesRow data containing date values
columnsColumn[]YesColumn definitions
configCalendarViewConfigYesCalendar view configuration
onRowClick(row: Row) => voidNoHandler when clicking an event
onDayClick(date: Date, events: CalendarEvent[]) => voidNoHandler when clicking a day
onDateChange(date: Date) => voidNoHandler when navigating months
isLoadingbooleanNoShow loading state
classNamestringNoCustom CSS class
styleCSSPropertiesNoInline styles

RelationCell

Cell component for displaying and editing relation values.

<RelationCell
  value={relationValues}
  onChange={(values) => {}}
  config={relationConfig}
  readOnly={false}
  onSearchRows={(tableId, query) => {}}
  onGetRowTitle={(tableId, rowId) => {}}
/>

Props

NameTypeRequiredDescription
valueRelationValue[] | nullYesCurrent relation values
onChange(value: RelationValue[]) => voidYesHandler for value changes
configRelationColumnConfigYesRelation column configuration
readOnlybooleanNoDisable editing
onSearchRows(tableId: string, query: string) => Promise<Row[]>NoCallback to search rows in target table
onGetRowTitle(tableId: string, rowId: string) => Promise<string>NoCallback to get display title for a row

RelationPicker

Popup picker component for selecting related rows.

<RelationPicker
  targetTableId={tableId}
  selectedRowIds={selectedIds}
  onSelect={(rowId, displayValue) => {}}
  onDeselect={(rowId) => {}}
  onClose={() => {}}
  limitType="multiple"
  position={{ top: 100, left: 200 }}
  onSearchRows={(query) => {}}
/>

Props

NameTypeRequiredDescription
targetTableIdstringYesID of the table to select rows from
selectedRowIdsstring[]YesCurrently selected row IDs
onSelect(rowId: string, displayValue: string) => voidYesHandler when row is selected
onDeselect(rowId: string) => voidYesHandler when row is deselected
onClose() => voidYesHandler to close the picker
limitType'single' | 'multiple'YesSingle or multiple selection mode
position{ top: number; left: number }YesPosition for the picker popup
onSearchRows(query: string) => Promise<Row[]>YesCallback to search rows

Types

View

interface View {
  id: string;
  tableId: string;
  name: string;
  type: ViewType;
  isDefault: boolean;
  position: number;
  config: ViewConfig;
  createdAt: Date;
  updatedAt: Date;
}

ViewType

type ViewType = 'table' | 'board' | 'calendar' | 'gallery' | 'timeline' | 'list';

ViewConfig

interface ViewConfig {
  filters?: QueryFilter[];
  sorts?: QuerySort[];
  groupBy?: string; // columnId for grouping
  boardConfig?: BoardViewConfig;
  calendarConfig?: CalendarViewConfig;
  galleryConfig?: GalleryViewConfig;
  timelineConfig?: TimelineViewConfig;
  listConfig?: ListViewConfig;
}

BoardViewConfig

interface BoardViewConfig {
  groupByColumnId: string;      // must be select/multi_select
  showEmptyGroups?: boolean;
  cardProperties?: string[];    // columnIds to show on cards
}

CalendarViewConfig

interface CalendarViewConfig {
  dateColumnId: string;
  endDateColumnId?: string;     // for date ranges
}

GalleryViewConfig

interface GalleryViewConfig {
  coverColumnId?: string;       // file column for cover image
  cardSize?: 'small' | 'medium' | 'large';
  cardProperties?: string[];    // columnIds to show on cards
}

TimelineViewConfig

interface TimelineViewConfig {
  startDateColumnId: string;
  endDateColumnId?: string;
  groupByColumnId?: string;
}

ListViewConfig

interface ListViewConfig {
  showCheckboxes?: boolean;
  indentColumnId?: string;      // for nested lists
}

CreateViewInput

interface CreateViewInput {
  tableId: string;
  name: string;
  type: ViewType;
  isDefault?: boolean;
  position?: number;
  config?: ViewConfig;
}

UpdateViewInput

interface UpdateViewInput {
  name?: string;
  type?: ViewType;
  isDefault?: boolean;
  config?: ViewConfig;
}

Column

interface Column {
  id: string;
  tableId: string;
  name: string;
  type: ColumnType;
  position: number;
  width: number;
  isPrimary: boolean;
  config?: ColumnConfig;
  createdAt: Date;
}

ColumnType

type ColumnType =
  | 'text'
  | 'number'
  | 'date'
  | 'boolean'
  | 'select'
  | 'multi_select'
  | 'url'
  | 'file'
  | 'formula'
  | 'relation'
  | 'rollup';

FormulaColumnConfig

Configuration for formula columns.

interface FormulaColumnConfig {
  formula: string;              // The formula expression
  resultType: 'text' | 'number' | 'date' | 'boolean';
}

RollupColumnConfig

Configuration for rollup columns that aggregate values from related rows.

interface RollupColumnConfig {
  relationColumnId: string;     // ID of the relation column to traverse
  targetColumnId: string;       // ID of the column to aggregate from related rows
  aggregation: RollupAggregation;
}

type RollupAggregation =
  | 'count'           // Count of related rows
  | 'sum'             // Sum of numeric values
  | 'average'         // Average of numeric values
  | 'min'             // Minimum value
  | 'max'             // Maximum value
  | 'countValues'     // Count of non-empty values
  | 'countUnique'     // Count of unique values
  | 'countEmpty'      // Count of empty values
  | 'countNotEmpty'   // Count of non-empty values (alias)
  | 'percentEmpty'    // Percentage of empty values (0-100)
  | 'percentNotEmpty' // Percentage of non-empty values (0-100)
  | 'showOriginal'    // Array of all values
  | 'showUnique';     // Array of unique values

RelationColumnConfig

Configuration for relation columns that link to rows in other tables.

interface RelationColumnConfig {
  targetTableId: string;        // ID of the table to link to
  bidirectional?: boolean;      // Create reverse relation automatically
  reverseColumnId?: string;     // ID of the reverse relation column
  limitType?: 'single' | 'multiple';  // Single or multiple row links
}

RelationValue

Value stored in relation cells.

interface RelationValue {
  rowId: string;                // ID of the linked row
  displayValue?: string;        // Cached title for display
}

Row

interface Row {
  id: string;
  tableId: string;
  cells: Record<string, CellValue>;
  computed?: Record<string, CellValue>; // Cached formula/rollup values
  archived: boolean;
  createdAt: Date;
  updatedAt: Date;
}

CellValue

type CellValue =
  | string
  | number
  | boolean
  | Date
  | null
  | string[]           // For multi_select
  | FileReference[]    // For file columns
  | RelationValue[];   // For relation columns

SelectOption

interface SelectOption {
  id: string;
  columnId: string;
  name: string;
  color?: string;
  position: number;
}

QueryFilter

interface QueryFilter {
  columnId: string;
  operator: FilterOperator;
  value: CellValue;
}

type FilterOperator =
  | 'equals'
  | 'notEquals'
  | 'contains'
  | 'notContains'
  | 'startsWith'
  | 'endsWith'
  | 'greaterThan'
  | 'greaterThanOrEquals'
  | 'lessThan'
  | 'lessThanOrEquals'
  | 'isEmpty'
  | 'isNotEmpty'
  | 'isIn'
  | 'isNotIn';

QuerySort

interface QuerySort {
  columnId: string;
  direction: 'asc' | 'desc';
}

DatabaseAdapter Interface

Implement this interface to create a custom storage adapter.

interface DatabaseAdapter {
  // Tables
  createTable(input: CreateTableInput): Promise<Table>;
  getTable(tableId: string): Promise<Table | null>;
  updateTable(tableId: string, updates: UpdateTableInput): Promise<Table>;
  deleteTable(tableId: string): Promise<void>;
  listTables(workspaceId: string): Promise<Table[]>;

  // Columns
  createColumn(input: CreateColumnInput): Promise<Column>;
  getColumns(tableId: string): Promise<Column[]>;
  getColumn(columnId: string): Promise<Column | null>;
  updateColumn(columnId: string, updates: UpdateColumnInput): Promise<Column>;
  deleteColumn(columnId: string): Promise<void>;
  reorderColumns(tableId: string, columnIds: string[]): Promise<void>;

  // Select Options
  createSelectOption(input: CreateSelectOptionInput): Promise<SelectOption>;
  getSelectOptions(columnId: string): Promise<SelectOption[]>;
  updateSelectOption(optionId: string, updates: UpdateSelectOptionInput): Promise<SelectOption>;
  deleteSelectOption(optionId: string): Promise<void>;
  reorderSelectOptions(columnId: string, optionIds: string[]): Promise<void>;

  // Rows
  createRow(input: CreateRowInput): Promise<Row>;
  getRow(rowId: string): Promise<Row | null>;
  getRows(tableId: string, query?: QueryOptions): Promise<QueryResult<Row>>;
  updateRow(rowId: string, cells: Record<string, CellValue>): Promise<Row>;
  deleteRow(rowId: string): Promise<void>;
  archiveRow(rowId: string): Promise<void>;
  unarchiveRow(rowId: string): Promise<void>;
  bulkCreateRows(inputs: CreateRowInput[]): Promise<Row[]>;
  bulkDeleteRows(rowIds: string[]): Promise<void>;
  bulkArchiveRows(rowIds: string[]): Promise<void>;

  // Relations
  createRelation(input: CreateRelationInput): Promise<void>;
  deleteRelation(sourceRowId: string, columnId: string, targetRowId: string): Promise<void>;
  getRelatedRows(rowId: string, columnId: string): Promise<Row[]>;
  getRelationsForRow(rowId: string): Promise<Array<{ columnId: string; targetRowId: string }>>;

  // File References
  addFileReference(input: CreateFileRefInput): Promise<FileReference>;
  removeFileReference(fileRefId: string): Promise<void>;
  getFileReferences(rowId: string, columnId: string): Promise<FileReference[]>;
  reorderFileReferences(rowId: string, columnId: string, fileRefIds: string[]): Promise<void>;

  // Views
  createView(input: CreateViewInput): Promise<View>;
  getViews(tableId: string): Promise<View[]>;
  getView(viewId: string): Promise<View | null>;
  updateView(viewId: string, updates: UpdateViewInput): Promise<View>;
  deleteView(viewId: string): Promise<void>;
  reorderViews(tableId: string, viewIds: string[]): Promise<void>;

  // Transactions
  transaction<T>(fn: (tx: DatabaseAdapter) => Promise<T>): Promise<T>;
}

View Methods

createView

Creates a new view for a table.

createView(input: CreateViewInput): Promise<View>
ParameterTypeDescription
input.tableIdstringID of the table
input.namestringName of the view
input.typeViewTypeType of view (table, board, calendar, etc.)
input.isDefaultbooleanWhether this is the default view
input.positionnumberPosition in the view list
input.configViewConfigView-specific configuration

getViews

Gets all views for a table.

getViews(tableId: string): Promise<View[]>

getView

Gets a specific view by ID.

getView(viewId: string): Promise<View | null>

updateView

Updates an existing view.

updateView(viewId: string, updates: UpdateViewInput): Promise<View>

deleteView

Deletes a view.

deleteView(viewId: string): Promise<void>

reorderViews

Reorders views by their position.

reorderViews(tableId: string, viewIds: string[]): Promise<void>

Formula Engine

The FormulaEngine evaluates Notion-like formulas against row data.

FormulaEngine Class

import { FormulaEngine } from '@marlinjai/data-table-core';

const engine = new FormulaEngine(options?: FormulaEngineOptions);

Constructor Options

interface FormulaEngineOptions {
  throwOnError?: boolean;       // Throw errors instead of returning null
  maxDepth?: number;            // Maximum recursion depth (default: 100)
  customFunctions?: Record<string, (...args: FormulaValue[]) => FormulaValue>;
}

Methods

evaluate

Evaluates a formula and returns the result.

engine.evaluate(formula: string, row: Row, columns: Column[]): CellValue
ParameterTypeDescription
formulastringThe formula expression to evaluate
rowRowThe row data containing cell values
columnsColumn[]Column definitions for the table

Returns: The computed value, or null on error.

Examples:

// Simple arithmetic with property references
engine.evaluate('prop("Price") * prop("Quantity")', row, columns);
// Returns: 150 (if Price=10, Quantity=15)

// String concatenation
engine.evaluate('concat(prop("First Name"), " ", prop("Last Name"))', row, columns);
// Returns: "John Doe"

// Conditional logic
engine.evaluate('if(prop("Status") == "Complete", "Done", "In Progress")', row, columns);
// Returns: "Done" or "In Progress"

// Math functions
engine.evaluate('round(prop("Price") * 1.08, 2)', row, columns);
// Returns: 10.80
evaluateWithResult

Evaluates a formula and returns both the result and any error.

engine.evaluateWithResult(formula: string, row: Row, columns: Column[]): FormulaResult

interface FormulaResult {
  value: CellValue;
  error?: string;
}
validate

Validates a formula without evaluating it.

engine.validate(formula: string): { isValid: boolean; error?: string }
getAST

Returns the parsed Abstract Syntax Tree for debugging.

engine.getAST(formula: string): ASTNode
addFunctions

Adds custom functions to the engine.

engine.addFunctions(functions: Record<string, (...args: FormulaValue[]) => FormulaValue>): void
clearCache

Clears the AST cache.

engine.clearCache(): void

Supported Operators

OperatorDescriptionExample
+Addition / String concatenation1 + 2, "a" + "b"
-Subtraction5 - 3
*Multiplication4 * 5
/Division10 / 2
%Modulo10 % 3
==Equalityprop("Status") == "Done"
!=Inequalityprop("Count") != 0
>Greater thanprop("Price") > 100
<Less thanprop("Age") < 18
>=Greater than or equalprop("Score") >= 70
<=Less than or equalprop("Qty") <= 10
andLogical ANDprop("A") and prop("B")
orLogical ORprop("A") or prop("B")
notLogical NOTnot prop("Archived")

Built-in Functions

The formula engine includes many built-in functions including:

  • Math: abs, ceil, floor, round, sqrt, pow, min, max
  • String: concat, length, lower, upper, trim, substring, replace, contains
  • Date: now, today, dateAdd, dateSub, year, month, day
  • Logic: if, and, or, not, empty, coalesce

FormulaParser Class

The FormulaParser parses formula strings into an Abstract Syntax Tree (AST).

import { FormulaParser } from '@marlinjai/data-table-core';

const parser = new FormulaParser();
const ast = parser.parse(formula: string): ASTNode;

AST Node Types

type ASTNode =
  | NumberLiteral       // e.g., 42, 3.14
  | StringLiteral       // e.g., "hello"
  | BooleanLiteral      // true, false
  | PropertyReference   // prop("Column Name")
  | BinaryExpression    // a + b, x == y
  | UnaryExpression     // not x, -5
  | FunctionCall        // concat("a", "b")
  | ConditionalExpression;  // condition ? true : false

FormulaParseError

Thrown when parsing fails.

class FormulaParseError extends Error {
  position: number;  // Position in the formula where error occurred
}

Rollup Engine

The RollupEngine calculates aggregated values from related rows.

RollupEngine Class

import { RollupEngine } from '@marlinjai/data-table-core';

const engine = new RollupEngine();

calculate

Calculates a rollup value based on the configuration and related rows.

engine.calculate(
  config: RollupColumnConfig,
  relatedRows: Row[],
  targetColumn: Column
): RollupResult

type RollupResult = number | CellValue[] | null;
ParameterTypeDescription
configRollupColumnConfigRollup configuration
relatedRowsRow[]Array of related rows
targetColumnColumnThe column to aggregate

Examples:

const engine = new RollupEngine();

// Sum prices from related line items
const total = engine.calculate(
  { relationColumnId: 'items', targetColumnId: 'price', aggregation: 'sum' },
  lineItemRows,
  priceColumn
);
// Returns: 250.00

// Count related tasks
const taskCount = engine.calculate(
  { relationColumnId: 'tasks', targetColumnId: 'id', aggregation: 'count' },
  taskRows,
  idColumn
);
// Returns: 5

// Get unique categories
const categories = engine.calculate(
  { relationColumnId: 'products', targetColumnId: 'category', aggregation: 'showUnique' },
  productRows,
  categoryColumn
);
// Returns: ['Electronics', 'Books', 'Clothing']

// Calculate completion percentage
const percentComplete = engine.calculate(
  { relationColumnId: 'tasks', targetColumnId: 'completed', aggregation: 'percentNotEmpty' },
  taskRows,
  completedColumn
);
// Returns: 80 (80% of tasks are completed)

Aggregation Types

AggregationReturn TypeDescription
countnumberTotal count of related rows
countValuesnumberCount of non-empty values
countUniquenumberCount of unique values
countEmptynumberCount of empty/null values
countNotEmptynumberCount of non-empty values
sumnumberSum of numeric values
averagenumberAverage of numeric values
minnumberMinimum value (works with dates too)
maxnumberMaximum value (works with dates too)
percentEmptynumberPercentage of empty values (0-100)
percentNotEmptynumberPercentage of non-empty values (0-100)
showOriginalCellValue[]Array of all non-empty values
showUniqueCellValue[]Array of unique non-empty values