Embeddable analytical query engine for MoonBit: run SQL over CSV/Parquet files, native and WebAssembly from one codebase.

git clone https://github.com/superbigcup325/moonlake && cd moonlake
moon update
moon run cmd/main -- exec --csv harness/data/sf001/lineitem.csv \
"SELECT l_returnflag, sum(l_extendedprice) FROM lineitem WHERE l_shipdate <= date '1998-09-02' GROUP BY l_returnflag ORDER BY l_returnflag"
# l_returnflag|sum_2
# A|532348211.6499983
# ...moon build cmd/main --target native --release
install -m755 _build/native/release/build/cmd/main/main.exe ~/.local/bin/moonlake
moonlake exec --csv lineitem.csv --file q6.sql # SQL from a file: no shell quotingimport {
"superbigcup325/moonlake",
"superbigcup325/moonlake/catalog",
"superbigcup325/moonlake/sources/csv",
}// a @catalog.Catalog with registered table entries — @csv/@parquet
// scan into one; note the argument order: content/name, not name/content.
// registration is lazy: the schema is available at once, and a query decodes
// only the columns it projects, in 2048-row batches
///|
fn main raise {
let cat = @catalog.Catalog::new()
cat.register(@csv.scan_string("region,amount\nnorth,100\n", "events"))
// read results back cell by cell: names() gives the columns,
// row_count() the rows, get(row, col) a @types.Scalar (null via Null)
let result = @moonlake.execute(
"SELECT region, count(*) FROM events GROUP BY region", cat,
)
for r in 0..<result.row_count() {
println(result.get(r, 0).to_string() + "|" + result.get(r, 1).to_string())
}
}uv run --with duckdb python harness/gen_tpch.py # TPC-H SF0.01 data + goldens
bash harness/check_all.sh # 33 goldens: all PASS (22 TPC-H + parquet + encoding variants)
MOONLAKE_DATA=harness/data/sf01 bash harness/check_all.sh # same at SF0.1 (regenerate first: gen_tpch.py 0.1)| query | moonlake native | duckdb |
|---|---|---|
| Pricing Summary Report (q1) | 100 ms | 3.5 ms |
| Forecasting Revenue Change (q6) | 68 ms | 1.1 ms |
| Product Type Profit Measure (q9) | 93 ms | 4.7 ms |
| Shipping Modes and Order Priority (q12) | 89 ms | 2.6 ms |
| project | what it is | boundary with moonlake |
|---|---|---|
| moonbit-community/sqlparser | SQL lexer/parser (AST) | parsing only, no execution; moonlake runs its own front-end (sql/) because sqlparser's select-statement AST is not destructurable cross-package, so the relationship is upstream cooperation, not a planned swap-in |
| apache/parquet-format | Parquet format and encoding specs | moonlake implements the decoding itself, diffed against DuckDB answers; the specification stays upstream |
| shunge/arrow (MoonArrow) | Arrow IPC format read/write | memory-format interchange; a future to_arrow bridge is cooperation, not competition |
| uiwcvb/moonsql | embedded OLTP database (row storage, CRUD, persistence) | different species — SQLite to moonlake's DuckDB: transactional storage vs external-file analytics |
| f4ah6o/duckdb, mizchi/duckdb | DuckDB C++ bindings | FFI route; the wasm-gc target is a stub upstream and the binding build is unstable, so moonlake is pure MoonBit and runs natively in the browser |
| path | what lives there |
|---|---|
| sql/ | lexer, parser and AST |
| types/ | Scalar, DataType, DataBatch and value encodings |
| catalog/ | table registration and the scan interface |
| sources/csv/, sources/parquet/ | CSV inference and scanning; the in-house Parquet reader and writer |
| engine/ | binder, plan, vectorized operators, joins, aggregates, windows, streaming |
| spill/ | the spill store used by the larger-than-memory operators |
| cmd/main/ | the moonlake command-line binary |
| playground/ | the wasm-gc browser page |
| examples/ | the README's library snippets as compiled packages |
| harness/ | TPC-H generation, golden comparisons, benchmarks and CI drivers |
| docs/ | demo, verification report, roadmap, devlog and design surveys |
moon check # type-check
moon test # run tests on the preferred target (wasm-gc)
moon test --target native # filesystem/native backend tests
moon fmt # format
moon run cmd/main # run the CLI
git config core.hooksPath hooks # once per clone: pre-commit gatemoon update # refresh the registry index; the graph downloads on the first check
moon checkln -s ../colenc .colenc
printf 'members = [".", "./.colenc"]\n' > moon.worklet VERSION : Stringlet s = @moonlake.stream("SELECT * FROM t LIMIT 3", cat)
while s.next() is Some(batch) {
inspect(batch.row_count())
}Install
Download zipEmbeddable analytical query engine for MoonBit: run SQL over CSV/Parquet files, native and WebAssembly from one codebase.