parquet

Parquet reader/writer for MoonBit.

moonbit
parquet
moon add mizchi/parquet@0.2.1
Download zip
Author
Version
0.2.1
License
Apache-2.0
Last updated
3 months ago
Downloads
1K

Dependencies

README

#mizchi/parquet

Parquet reader/writer for MoonBit.

#Status

  • Reader passes the vendored apache-parquet-testing fixtures used in this repo:
    • delta_binary_packed
    • delta_byte_array
    • delta_encoding_optional_column
    • delta_encoding_required_column
    • int32_with_null_pages
    • fixed_length_byte_array
    • datapage_v2_empty_datapage.snappy.parquet
    • int96_from_spark
    • alltypes_plain
    • alltypes_dictionary
  • Writer currently supports flat schemas with Int32, Int64, String, and Binary, with Required / Optional repetition.
  • DuckDB interoperability is checked both ways:
    • DuckDB-written parquet can be read by this implementation.
    • MoonBit-written parquet can be read by DuckDB.

#Benchmark

Measured on 2026-03-09 on Apple M5, macOS 26.2, Darwin arm64.

Reproduce:

just bench-compare-all just bench-compare-rust

Comparison table from just bench-compare-all:

benchmarkmoon(js)moon(wasm-gc)moon(native)rust
read delta binary packed benchmark512.22 us127.01 us645.99 us203.85 us
read int32 null pages benchmark17.34 us10.85 us43.60 us7.61 us
read fixed length byte array benchmark87.17 us10.41 us54.68 usunsupported
read alltypes plain benchmark20.49 us12.02 us45.42 us19.57 us
read alltypes dictionary benchmark16.83 us11.04 us42.53 us17.31 us
read int96 from spark benchmark10.90 us3.52 us16.19 us3.28 us
read empty snappy datapage v2 benchmark3.46 us1.72 us6.27 us2.58 us

Notes:

  • Rust is the local baseline in tools/rust-bench, built on top of Apache's parquet crate.
  • fixed_length_byte_array is marked unsupported because the current Rust benchmark tool does not read that fixture.
  • On this machine, wasm-gc is the fastest MoonBit target for the read-side microbenchmarks above.

#Development

just # check + test just target=js bench just target=wasm-gc bench just target=native bench just bench-compare-all just e2e-duckdb moon info

#Browser Playground

The repository includes a browser playground that generates parquet on DuckDB WASM and lets you try SQL against it immediately.

just playground-install just playground-dev

Production build:

just playground-build just playground-build-pages

In the UI, you can edit schema JSON / rows JSON / SQL, generate parquet bytes with mizchi/parquet, and execute read_parquet('playground.parquet') on the f4ah6o/duckdb WASM backend.

GitHub Pages:

https://mizchi.github.io/parquet/

#License

Apache-2.0

#
ParquetError

pub(all) suberror ParquetError {
InvalidData(String)
Unsupported(String)
Io(String)
} derive(Eq)

#
Column

pub struct Column {
name : String
column_type : ColumnType
repetition : Repetition
} derive(Eq)

impl Show for Column

#
Column::column_type

fn Column::column_type(self : Column) -> ColumnType

#
Column::name

fn Column::name(self : Column) -> String

#
Column::repetition

fn Column::repetition(self : Column) -> Repetition

#
ColumnType

pub(all) enum ColumnType {
Boolean
Int32
Int64
TimestampMicros
Float
Double
String
Binary
} derive(Eq)

impl Show for ColumnType

#
ParquetColumnData

pub(all) enum ParquetColumnData {
Values(Array[Value])
BooleanValues(Array[Bool])
Int32Values(Array[Int])
NullableInt32Values(Array[Int?])
Int64Values(Array[Int64])
NullableInt64Values(Array[Int64?])
TimestampMicrosValues(Array[Int64])
NullableTimestampMicrosValues(Array[Int64?])
FloatValues(Array[Float])
DoubleValues(Array[Double])
Utf8Values(Array[Bytes])
NullableUtf8Values(Array[Bytes?])
BinaryValues(Array[Bytes])
NullableBinaryValues(Array[Bytes?])
} derive(Eq)

#
ParquetColumnData::length

fn ParquetColumnData::length(self : ParquetColumnData) -> Int

#
ParquetColumnarFile

pub struct ParquetColumnarFile {
columns : Array[Column]
column_data : Array[ParquetColumnData]
row_count : Int
column_values_cache : Array[Array[Value]]?
created_by : String?
}

#
ParquetColumnarFile::column_data

#
ParquetColumnarFile::column_values

#
ParquetColumnarFile::columns

#
ParquetColumnarFile::created_by

fn ParquetColumnarFile::created_by(self : ParquetColumnarFile) -> String?

#
ParquetColumnarFile::row_count

fn ParquetColumnarFile::row_count(self : ParquetColumnarFile) -> Int

#
ParquetFile

pub struct ParquetFile {
columns : Array[Column]
row_count : Int
column_data : Array[ParquetColumnData]
rows_cache : Array[Array[Value]]?
created_by : String?
}

impl Eq for ParquetFile
impl Show for ParquetFile

#
ParquetFile::column_data

fn ParquetFile::column_data(self : ParquetFile) -> Array[ParquetColumnData]

#
ParquetFile::columns

fn ParquetFile::columns(self : ParquetFile) -> Array[Column]

#
ParquetFile::created_by

fn ParquetFile::created_by(self : ParquetFile) -> String?

#
ParquetFile::row_count

fn ParquetFile::row_count(self : ParquetFile) -> Int

#
ParquetFile::rows

fn ParquetFile::rows(self : ParquetFile) -> Array[Array[Value]]

#
Repetition

pub(all) enum Repetition {
Required
Optional
Repeated
} derive(Eq)

impl Show for Repetition

#
Value

pub(all) enum Value {
Boolean(Bool)
Int32(Int)
Int64(Int64)
TimestampMicros(Int64)
Float(Float)
Double(Double)
String(String)
Binary(Bytes)
Null
} derive(Eq)

impl Show for Value

#
new_column

fn new_column(name : String, column_type : ColumnType, repetition : Repetition) -> Column

#
new_parquet_columnar_file

fn new_parquet_columnar_file(columns : Array[Column], column_data : Array[ParquetColumnData], row_count : Int, created_by : String?) -> ParquetColumnarFile

#
new_parquet_file

fn new_parquet_file(columns : Array[Column], rows : Array[Array[Value]], created_by : String?) -> ParquetFile

#
read_bytes

fn read_bytes(data : Bytes) -> ParquetFile raise ParquetError

Read a parquet document from bytes.

#
read_bytes_columnar

fn read_bytes_columnar(data : Bytes) -> ParquetColumnarFile raise ParquetError

Read a parquet document from bytes without row materialization.

#
read_file

fn read_file(path : String) -> ParquetFile raise ParquetError

Read a parquet file from disk.

#
read_file_columnar

fn read_file_columnar(path : String) -> ParquetColumnarFile raise ParquetError

Read a parquet file from disk without row materialization.

#
write_bytes

fn write_bytes(file : ParquetFile) -> Bytes raise ParquetError

Encode a parquet document to bytes.

The current writer supports flat schemas of Int32, Int64, String, and Binary, with Required or Optional repetition.

#
write_file

fn write_file(path : String, file : ParquetFile) -> Unit raise ParquetError

Encode a parquet document and write it to disk.

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io