DEVELOPER

TypeScript API Reference

The teide-js package exposes a fluent, chainable API for loading data, building queries, and accessing results. All heavy computation runs on a dedicated background thread, with both synchronous and asynchronous execution paths.

Context

The Context is the entry point for all Teide operations. It manages the native engine lifecycle, including the background Teide thread and the C heap.

class Context {
  constructor()
  readCsvSync(path: string): Table
  readCsv(path: string): Promise<Table>
  executeSync(sql: string): Table | null  // Table for queries, null for DDL/DML
  execute(sql: string): Promise<Table | null>
  destroy(): void  // Also available via Symbol.dispose
}

Creating and Disposing

import { Context } from 'teide-js';

// Create a new context
const ctx = new Context();

// Use it...

// Option 1: explicit cleanup
ctx.destroy();

// Option 2: using Symbol.dispose (requires TypeScript 5.2+ or Node 20+)
{
  using ctx = new Context();
  // ctx is automatically destroyed at end of block
}

Loading CSV Data

// Synchronous
const table = ctx.readCsvSync('data/sales.csv');
console.log(`Loaded ${table.nRows} rows, ${table.nCols} columns`);
console.log('Columns:', table.columns);

// Asynchronous
const table = await ctx.readCsv('data/sales.csv');

Executing SQL

// DDL returns null
ctx.executeSync(`CREATE TABLE users (id INTEGER, name VARCHAR, age INTEGER)`);

// DML returns null
ctx.executeSync(`INSERT INTO users VALUES (1, 'Alice', 30), (2, 'Bob', 25)`);

// Queries return a Table
const result = ctx.executeSync(`SELECT * FROM users WHERE age > 20`);
console.log(result.nRows); // 2

// Async execution
const result = await ctx.execute(`SELECT name, age FROM users ORDER BY age DESC`);

Table

A Table represents a columnar result set. It provides metadata, column access, and serves as the starting point for the fluent query API.

class Table {
  readonly nRows: number
  readonly nCols: number
  readonly columns: string[]
  col(name: string): Series
  filter(expr: Expr): Query
  groupBy(...cols: string[]): GroupBy
  sort(col: string, opts?: { descending?: boolean }): Query
  head(n: number): Query
}

Inspecting Results

const table = ctx.readCsvSync('sales.csv');

console.log(`${table.nRows} rows x ${table.nCols} cols`);
console.log('Column names:', table.columns);

// Access individual columns
const revenue = table.col('revenue');
console.log('Revenue dtype:', revenue.dtype);
console.log('First 5 values:', Array.from(revenue.data.slice(0, 5)));

Starting Queries from a Table

import { col, lit } from 'teide-js';

// Filter
const expensive = table
  .filter(col('price').gt(lit(100)))
  .collectSync();

// Sort
const sorted = table
  .sort('revenue', { descending: true })
  .collectSync();

// Head (first N rows)
const preview = table.head(10).collectSync();

// Group by
const summary = table
  .groupBy('region')
  .agg(col('revenue').sum().alias('total_revenue'))
  .collectSync();

Series

A Series represents a single column of data. It provides zero-copy access to the underlying C heap memory via TypedArrays — no data is copied between the native engine and JavaScript.

class Series {
  readonly name: string
  readonly dtype: string
  readonly length: number
  readonly data: TypedArray  // Float64Array, Int32Array, BigInt64Array, etc.
  readonly nullBitmap: Uint8Array | null
  readonly indices: Int32Array | null      // for SYM (dictionary) columns
  readonly dictionary: string[] | null     // for SYM (dictionary) columns
}

Numeric Columns

const prices = table.col('price');
console.log(prices.dtype);   // "F64"
console.log(prices.length);  // 1000

// Direct TypedArray access (zero-copy)
const data = prices.data;    // Float64Array
const sum = data.reduce((a, b) => a + b, 0);
const avg = sum / data.length;

Dictionary (SYM) Columns

const regions = table.col('region');
console.log(regions.dtype);      // "SYM"
console.log(regions.dictionary); // ["North", "South", "East", "West"]
console.log(regions.indices);    // Int32Array [0, 1, 2, 0, 3, ...]

// Resolve the i-th value
const dict = regions.dictionary;
const idx = regions.indices;
for (let i = 0; i < regions.length; i++) {
  console.log(dict[idx[i]]);    // "North", "South", "East", ...
}

Null Handling

const ages = table.col('age');
const bitmap = ages.nullBitmap; // Uint8Array or null

if (bitmap) {
  for (let i = 0; i < ages.length; i++) {
    const byteIdx = i >> 3;
    const bitIdx = i & 7;
    const isNull = (bitmap[byteIdx] & (1 << bitIdx)) === 0;
    if (!isNull) {
      console.log(`Row ${i}: ${ages.data[i]}`);
    }
  }
}

Expr (Expression Builder)

Expressions represent computations that are evaluated lazily by the engine. Use the col() and lit() factory functions to create expression trees, then combine them with arithmetic, comparison, and logical operators.

function col(name: string): Expr
function lit(value: number | string | boolean): Expr

class Expr {
  // Arithmetic
  add(other: Expr): Expr
  sub(other: Expr): Expr
  mul(other: Expr): Expr
  div(other: Expr): Expr
  mod(other: Expr): Expr

  // Comparison
  eq(other: Expr): Expr
  ne(other: Expr): Expr
  lt(other: Expr): Expr
  le(other: Expr): Expr
  gt(other: Expr): Expr
  ge(other: Expr): Expr

  // Logical
  and(other: Expr): Expr
  or(other: Expr): Expr
  not(): Expr

  // Math
  abs(): Expr
  sqrt(): Expr
  log(): Expr
  exp(): Expr
  ceil(): Expr
  floor(): Expr
  neg(): Expr

  // Null
  isNull(): Expr

  // Aggregation
  sum(): Expr
  avg(): Expr
  mean(): Expr    // alias for avg()
  min(): Expr
  max(): Expr
  count(): Expr
  first(): Expr
  last(): Expr

  // Naming
  alias(name: string): Expr
}

Building Expressions

import { col, lit } from 'teide-js';

// Column reference
const price = col('price');

// Literal value
const threshold = lit(100);

// Arithmetic
const margin = col('revenue').sub(col('cost'));
const taxed = col('price').mul(lit(1.2));
const perUnit = col('total').div(col('quantity'));

// Comparison
const isExpensive = col('price').gt(lit(100));
const isInStock = col('quantity').gt(lit(0));

// Logical combination
const filter = isExpensive.and(isInStock);

// Math functions
const logPrice = col('price').log();
const absChange = col('delta').abs();

// Null check
const hasMissing = col('email').isNull();

// Aggregation with alias
const totalRevenue = col('revenue').sum().alias('total_revenue');
const avgPrice = col('price').avg().alias('avg_price');

Complete Example

import { Context, col, lit } from 'teide-js';

const ctx = new Context();
const sales = ctx.readCsvSync('sales.csv');

// Multi-step analysis pipeline
const result = sales
  .filter(col('quantity').gt(lit(0)))
  .groupBy('region')
  .agg(
    col('revenue').sum().alias('total_revenue'),
    col('revenue').avg().alias('avg_revenue'),
    col('price').min().alias('min_price'),
    col('price').max().alias('max_price'),
    col('revenue').count().alias('num_sales')
  )
  .sort('total_revenue', { descending: true })
  .head(10)
  .collectSync();

for (const name of result.columns) {
  console.log(`${name}:`, Array.from(result.col(name).data));
}

ctx.destroy();

Query

A Query represents a lazy chain of operations. No computation happens until you call collectSync() or collect(). Operations can be chained fluently.

class Query {
  filter(expr: Expr): Query
  groupBy(...cols: string[]): GroupBy
  sort(col: string, opts?: { descending?: boolean }): Query
  head(n: number): Query
  collectSync(): Table
  collect(): Promise<Table>
}

Chaining Operations

// All operations are lazy until collect
const query = table
  .filter(col('status').eq(lit('active')))
  .sort('created_at', { descending: true })
  .head(100);

// Execute synchronously
const result = query.collectSync();

// Or execute asynchronously
const result = await query.collect();

Filter then Group

const result = table
  .filter(col('year').ge(lit(2020)))
  .groupBy('category')
  .agg(
    col('sales').sum().alias('total'),
    col('sales').avg().alias('average')
  )
  .sort('total', { descending: true })
  .collectSync();

GroupBy

A GroupBy is created from a Table or Query via .groupBy(). Call .agg() with aggregation expressions to produce a new Query.

class GroupBy {
  agg(...exprs: Expr[]): Query
}

Aggregation Examples

// Single group key, multiple aggregations
const byRegion = table
  .groupBy('region')
  .agg(
    col('revenue').sum().alias('total'),
    col('revenue').avg().alias('avg'),
    col('revenue').count().alias('n')
  )
  .collectSync();

// Multiple group keys
const byRegionYear = table
  .groupBy('region', 'year')
  .agg(
    col('profit').sum().alias('total_profit'),
    col('profit').first().alias('first_profit'),
    col('profit').last().alias('last_profit')
  )
  .collectSync();