Universe

Query SQLite databases at compile time in Typst.

Built with Zig, compiled to WASM. Full SQL support including JOINs, CTEs, window functions, subqueries, and aggregations.

Quick Start

#import "@preview/typsqlite:0.1.0": sqlite, sqlite-table

#let db = sqlite(read("data.sqlite", encoding: none))

// Query and render as a table
#sqlite-table((db.query)("SELECT name, population FROM cities ORDER BY population DESC"))

// Use raw results
#let result = (db.query)("SELECT count(*) as n FROM cities")
Total cities: #result.rows.at(0).at(0)

API

sqlite(db-bytes)

Open a database from bytes. Returns an object with:

Method Returns Description
query(sql) {columns: [...], rows: [[...], ...]} Execute SQL query
tables() ("table1", "table2", ...) List table names
schema(table) {columns: [{name, type}, ...]} Get column info

sqlite-table(result, ..args)

Render query results as a Typst table. Extra arguments pass through to table().

#sqlite-table(
  (db.query)("SELECT * FROM cities"),
  fill: (x, y) => if y == 0 { gray.lighten(70%) },
)

query-table(db, sql)

Query and return flat cell array for use with table() directly:

#table(columns: 3, ..query-table(db, "SELECT name, country, pop FROM cities"))

How It Works

SQLite is compiled into a ~640KB WASM module. Typst reads database files as bytes, passes them to the plugin which opens them as an in-memory SQLite database (custom read-only VFS), executes queries, and returns JSON results.

Source

github.com/jrossi/typst-wasm-sqlite