js/data/arrow
js/data/arrow/index.ts
fino:data/arrow — a pure-TypeScript implementation of Apache Arrow.
Provides the Arrow columnar in-memory format (every logical type, including
the view, union, map, dictionary, and run-end-encoded layouts) and the Arrow
IPC stream and file formats for interchange with the Arrow ecosystem
(pyarrow, polars, DuckDB, ...). The Arrow C Data Interface — zero-copy
hand-off of these same structures to native libraries over fino:ffi —
lives in the companion module fino:data/arrow/cdata.
The object model is Vector (one column), RecordBatch (a schema plus one
equal-length vector per field), and Table (a schema plus batches, with
chunked Column views that read one field across batch boundaries).
get(i) returns raw physical values — number up to 32 bits, bigint for
64-bit ints, timestamps, and durations, string, Uint8Array for binary,
arrays/objects for nested types, and null for nulls. Build vectors with
vectorFromArray (type inference from JS values) or makeVector (raw Arrow
buffers), and describe columns with the logical type factories (int32(),
utf8(), list(), dictionary(), ...) plus Field and Schema.
For interchange, tableToIPC serializes a Table or RecordBatch to IPC
bytes — the streaming format by default, { format: 'file' } for the
random-access file format, optionally with lz4 or zstd body compression
— and tableFromIPC decodes either format back into a Table. The
RecordBatchReader/RecordBatchFileReader and
RecordBatchStreamWriter/RecordBatchFileWriter classes expose the same
machinery batch by batch. Malformed input throws ArrowParseError, which
carries the failing byte offset and renders a hex dump of the offending
region; structural misuse (ragged columns, mismatched schemas) throws
ArrowError.
import { RecordBatch, tableToIPC, tableFromIPC } from 'fino:data/arrow';
const batch = RecordBatch.from({ id: [1, 2, 3], name: ['a', 'b', 'c'] });
const bytes = tableToIPC(batch); // Arrow IPC stream bytes
const table = tableFromIPC(bytes); // also accepts pyarrow/polars output
table.getChild('name')!.toArray(); // ['a', 'b', 'c']
Useful references: - Arrow columnar format: https://arrow.apache.org/docs/format/Columnar.html - Arrow IPC format: https://arrow.apache.org/docs/format/Columnar.html#serialization-and-interprocess-communication-ipc - Arrow C Data Interface: https://arrow.apache.org/docs/format/CDataInterface.html
Constants
const Type
Arrow Type union tags (from Schema.fbs). Used as the typeId on every
DataType and as the union discriminant in IPC metadata.
Prefer matching on a type's kind string in JS code; the numeric ids exist
for IPC and C Data Interface interop.
const TimeUnit
Time/timestamp/duration units (Arrow TimeUnit), from whole seconds down
to nanoseconds. Passed to time32/time64/timestamp/duration and
stored on the resulting type's unit property.
const DateUnit
Date units (Arrow DateUnit): DAY for date32 (days since the Unix
epoch) and MILLISECOND for date64 (milliseconds since the Unix epoch).
const IntervalUnit
Interval units (Arrow IntervalUnit). Selects the physical encoding of an
interval(...) type: a 4-byte month count (YEAR_MONTH), an 8-byte
day + millisecond pair (DAY_TIME), or a 16-byte month/day/nanosecond
triple (MONTH_DAY_NANO).
const UnionMode
Union modes (Arrow UnionMode). Sparse unions store every child column
at the union's full length; Dense unions add a 32-bit offsets buffer so
each child stores only its own values.
const Precision
Floating-point precisions (Arrow Precision): half (16-bit), single
(32-bit), and double (64-bit). Stored on FloatType.precision.
const nullType
Builds the null type. Named nullType because null is a reserved word.
import { nullType } from 'fino:data/arrow';
const t = nullType();
const bool
Builds the bit-packed boolean type.
import { bool } from 'fino:data/arrow';
const t = bool();
const int8
Builds a signed 8-bit integer type.
import { int8 } from 'fino:data/arrow';
const t = int8();
const int16
Builds a signed 16-bit integer type.
import { int16 } from 'fino:data/arrow';
const t = int16();
const int32
Builds a signed 32-bit integer type.
import { int32 } from 'fino:data/arrow';
const t = int32();
const int64
Builds a signed 64-bit integer type.
import { int64 } from 'fino:data/arrow';
const t = int64();
const uint8
Builds an unsigned 8-bit integer type.
import { uint8 } from 'fino:data/arrow';
const t = uint8();
const uint16
Builds an unsigned 16-bit integer type.
import { uint16 } from 'fino:data/arrow';
const t = uint16();
const uint32
Builds an unsigned 32-bit integer type.
import { uint32 } from 'fino:data/arrow';
const t = uint32();
const uint64
Builds an unsigned 64-bit integer type.
import { uint64 } from 'fino:data/arrow';
const t = uint64();
const float16
Builds a half-precision (16-bit) floating-point type.
import { float16 } from 'fino:data/arrow';
const t = float16();
const float32
Builds a single-precision (32-bit) floating-point type.
import { float32 } from 'fino:data/arrow';
const t = float32();
const float64
Builds a double-precision (64-bit) floating-point type.
import { float64 } from 'fino:data/arrow';
const t = float64();
const decimal
Builds a fixed-point decimal type with precision total digits and
scale fractional digits. Storage defaults to 128 bits, the common width
for SQL-style decimals up to 38 digits.
import { decimal } from 'fino:data/arrow';
const price = decimal(10, 2); // 128-bit
const tiny = decimal(7, 3, 32); // 32-bit storage
const date32
Builds a day-precision date type (32-bit days since the Unix epoch).
import { date32 } from 'fino:data/arrow';
const t = date32();
const date64
Builds a millisecond-precision date type (64-bit milliseconds since the Unix epoch).
import { date64 } from 'fino:data/arrow';
const t = date64();
const time32
Builds a 32-bit time-of-day type; defaults to milliseconds. The Arrow spec
pairs 32-bit times with SECOND or MILLISECOND units — the unit is not
validated here, but other tooling will reject finer units at this width.
import { time32, TimeUnit } from 'fino:data/arrow';
const t = time32(TimeUnit.SECOND);
const time64
Builds a 64-bit time-of-day type; defaults to microseconds. The Arrow spec
pairs 64-bit times with MICROSECOND or NANOSECOND units.
import { time64, TimeUnit } from 'fino:data/arrow';
const t = time64(TimeUnit.NANOSECOND);
const timestamp
Builds a timestamp type; defaults to zone-naive microseconds. Pass a timezone string to mark values as absolute instants in that zone.
import { timestamp, TimeUnit } from 'fino:data/arrow';
const created = timestamp(TimeUnit.MILLISECOND, 'UTC');
const duration
Builds a duration type (64-bit elapsed-time counts); defaults to microseconds.
import { duration, TimeUnit } from 'fino:data/arrow';
const t = duration(TimeUnit.NANOSECOND);
const interval
Builds a calendar-interval type. The unit is required because it changes the physical width (4, 8, or 16 bytes per value).
import { interval, IntervalUnit } from 'fino:data/arrow';
const t = interval(IntervalUnit.DAY_TIME);
const utf8
Builds the UTF-8 string type with 32-bit offsets.
import { utf8 } from 'fino:data/arrow';
const t = utf8();
const largeUtf8
Builds the UTF-8 string type with 64-bit offsets.
import { largeUtf8 } from 'fino:data/arrow';
const t = largeUtf8();
const binary
Builds the variable-length binary type with 32-bit offsets.
import { binary } from 'fino:data/arrow';
const t = binary();
const largeBinary
Builds the variable-length binary type with 64-bit offsets.
import { largeBinary } from 'fino:data/arrow';
const t = largeBinary();
const utf8View
Builds the view-layout UTF-8 string type (16-byte views plus variadic data buffers).
import { utf8View } from 'fino:data/arrow';
const t = utf8View();
const binaryView
Builds the view-layout binary type (16-byte views plus variadic data buffers).
import { binaryView } from 'fino:data/arrow';
const t = binaryView();
const fixedSizeBinary
Builds a fixed-size binary type of exactly byteWidth bytes per value.
import { fixedSizeBinary } from 'fino:data/arrow';
const sha256 = fixedSizeBinary(32);
const list
Builds a list type with 32-bit offsets over the given element field.
import { list, utf8, Field } from 'fino:data/arrow';
const tags = list(new Field('item', utf8()));
const largeList
Builds a list type with 64-bit offsets over the given element field.
import { largeList, binary, Field } from 'fino:data/arrow';
const blobs = largeList(new Field('item', binary()));
const listView
Builds a list-view type (32-bit offsets and sizes) over the given element field.
import { listView, int32, Field } from 'fino:data/arrow';
const t = listView(new Field('item', int32()));
const largeListView
Builds a large list-view type (64-bit offsets and sizes) over the given element field.
import { largeListView, int32, Field } from 'fino:data/arrow';
const t = largeListView(new Field('item', int32()));
const fixedSizeList
Builds a fixed-size list type: every value holds exactly listSize
elements of the given field.
import { fixedSizeList, float32, Field } from 'fino:data/arrow';
const embedding = fixedSizeList(768, new Field('item', float32(), false));
const struct
Builds a struct type from its member fields.
import { struct, utf8, int32, Field } from 'fino:data/arrow';
const person = struct([
new Field('name', utf8(), false),
new Field('age', int32()),
]);
const map
Builds a map type over an entries struct field. The child should be a
non-nullable struct field with a non-nullable key field and a value field;
pass keysSorted: true only when keys are sorted within each map value.
import { map, struct, utf8, int32, Field } from 'fino:data/arrow';
const t = map(new Field('entries', struct([
new Field('key', utf8(), false),
new Field('value', int32()),
]), false));
const union
Builds a union type. typeIds[i] is the tag written to the typeIds buffer
for values of child i; tags need not be contiguous or start at zero.
import { union, UnionMode, int32, utf8, Field } from 'fino:data/arrow';
const t = union(UnionMode.Dense, [0, 1], [
new Field('num', int32()),
new Field('str', utf8()),
]);
const dictionary
Builds a dictionary-encoded type: indexType codes referencing a
dictionary of valueType values. The id ties the field to its
dictionary batch in IPC streams; distinct dictionaries in one schema need
distinct ids. The resulting typeId mirrors valueType.typeId.
import { dictionary, int8, utf8 } from 'fino:data/arrow';
const color = dictionary(0, int8(), utf8());
const runEndEncoded
Builds a run-end encoded type from its two child fields: runEnds (a
non-nullable integer field of exclusive run end indices) and values
(one value per run).
import { runEndEncoded, int32, utf8, Field } from 'fino:data/arrow';
const t = runEndEncoded(
new Field('run_ends', int32(), false),
new Field('values', utf8()),
);
Types
type BufferKind = 'validity' | 'offset32' | 'offset64' | 'size32' | 'size64' | 'data' | 'typeIds' | 'views'
A logical component of a type's physical buffer layout, in Arrow order.
validity is the null bitmap, offset32/offset64 are value offsets,
size32/size64 are list-view sizes, data is the values buffer,
typeIds is the union type-id buffer, and views is the 16-byte view
buffer used by the Utf8View/BinaryView types.
type DataType = NullType | BoolType | IntType | FloatType | DecimalType | DateType | TimeType | TimestampType | IntervalType | DurationType | Utf8Type | LargeUtf8Type | BinaryType | LargeBinaryType | Utf8ViewType | BinaryViewType | FixedSizeBinaryType | ListType | LargeListType | ListViewType | LargeListViewType | FixedSizeListType | StructType | MapType | UnionType | DictionaryType | RunEndEncodedType
Any Arrow logical type. Narrow on the kind discriminant in a switch to
recover the concrete member.
Interfaces
interface BaseType {
Base shape shared by every DataType.
Readonly Properties
readonly typeId: number
Numeric Arrow Type union tag, for IPC and C Data Interface interop.
readonly kind: string
Lowercase discriminant string that narrows the DataType union.
interface NullType extends BaseType {
The null type: every value is null, and no buffers are allocated at all.
import { nullType, bufferLayout } from 'fino:data/arrow';
const t = nullType();
bufferLayout(t); // []
Properties
kind: 'null'
typeId: 1
interface BoolType extends BaseType {
Boolean type. Values are bit-packed in the data buffer, eight per byte, so
fixedWidthBytes reports 0 for it despite the fixed layout.
import { bool } from 'fino:data/arrow';
const t = bool(); // { kind: 'bool', typeId: 6 }
Properties
kind: 'bool'
typeId: 6
interface IntType extends BaseType {
Fixed-width integer of 8 to 64 bits, signed or unsigned. Built by the
int8..int64 and uint8..uint64 factories.
import { int32, uint64 } from 'fino:data/arrow';
const a = int32(); // bitWidth 32, signed true
const b = uint64(); // bitWidth 64, signed false
Properties
kind: 'int'
typeId: 2
bitWidth: 8 | 16 | 32 | 64
Bits per value: 8, 16, 32, or 64.
signed: boolean
Whether values are two's-complement signed.
interface FloatType extends BaseType {
IEEE 754 floating-point number in half, single, or double precision.
import { float64, Precision } from 'fino:data/arrow';
const t = float64();
t.precision === Precision.DOUBLE; // true
Properties
kind: 'float'
typeId: 3
precision: number
One of the Precision constants: HALF, SINGLE, or DOUBLE.
interface DecimalType extends BaseType {
Fixed-point decimal: precision total significant digits with scale
digits after the decimal point, stored as a little-endian two's-complement
integer of bitWidth bits.
import { decimal } from 'fino:data/arrow';
const money = decimal(38, 9); // 128-bit storage by default
Properties
kind: 'decimal'
typeId: 7
precision: number
Total number of significant digits.
scale: number
Number of digits after the decimal point.
bitWidth: 32 | 64 | 128 | 256
Storage width in bits.
interface DateType extends BaseType {
Calendar date. DateUnit.DAY stores 32-bit days since the Unix epoch
(date32); DateUnit.MILLISECOND stores 64-bit milliseconds since the
epoch (date64).
import { date32, DateUnit } from 'fino:data/arrow';
const t = date32();
t.unit === DateUnit.DAY; // true
Properties
kind: 'date'
typeId: 8
unit: number
One of the DateUnit constants: DAY or MILLISECOND.
interface TimeType extends BaseType {
Time of day since midnight, as a 32- or 64-bit integer in unit
resolution. The Arrow spec pairs 32-bit storage with second/millisecond
units and 64-bit storage with microsecond/nanosecond units.
import { time64, TimeUnit } from 'fino:data/arrow';
const t = time64(TimeUnit.NANOSECOND); // bitWidth 64
Properties
kind: 'time'
typeId: 9
unit: number
One of the TimeUnit constants.
bitWidth: 32 | 64
Storage width in bits: 32 for time32, 64 for time64.
interface TimestampType extends BaseType {
An instant: a 64-bit count of unit intervals since the Unix epoch. With
a timezone the values are absolute instants displayed in that zone; with
timezone: null they are zone-naive wall-clock readings.
import { timestamp, TimeUnit } from 'fino:data/arrow';
const utc = timestamp(TimeUnit.MILLISECOND, 'UTC');
const naive = timestamp(); // microseconds, no timezone
Properties
kind: 'timestamp'
typeId: 10
unit: number
One of the TimeUnit constants.
timezone: string | null
IANA zone name or fixed offset string, or null for zone-naive.
interface IntervalType extends BaseType {
Calendar interval. The unit selects the physical encoding: months only
(YEAR_MONTH), days plus milliseconds (DAY_TIME), or months, days, and
nanoseconds (MONTH_DAY_NANO).
import { interval, IntervalUnit } from 'fino:data/arrow';
const t = interval(IntervalUnit.MONTH_DAY_NANO); // 16 bytes per value
Properties
kind: 'interval'
typeId: 11
unit: number
One of the IntervalUnit constants.
interface DurationType extends BaseType {
Elapsed time as a 64-bit integer count of unit intervals, with no
calendar semantics (unlike IntervalType).
import { duration, TimeUnit } from 'fino:data/arrow';
const t = duration(TimeUnit.NANOSECOND);
Properties
kind: 'duration'
typeId: 18
unit: number
One of the TimeUnit constants.
interface Utf8Type extends BaseType {
Variable-length UTF-8 string with 32-bit offsets, which caps a single
column chunk's string data at 2 GiB. Use LargeUtf8Type beyond that.
import { utf8, bufferLayout } from 'fino:data/arrow';
bufferLayout(utf8()); // ['validity', 'offset32', 'data']
Properties
kind: 'utf8'
typeId: 5
interface LargeUtf8Type extends BaseType {
Variable-length UTF-8 string with 64-bit offsets, for columns whose string
data may exceed the 2 GiB limit of Utf8Type.
import { largeUtf8, bufferLayout } from 'fino:data/arrow';
bufferLayout(largeUtf8()); // ['validity', 'offset64', 'data']
Properties
kind: 'largeutf8'
typeId: 20
interface BinaryType extends BaseType {
Variable-length byte string with 32-bit offsets. Same layout as
Utf8Type but with no UTF-8 validity guarantee.
import { binary } from 'fino:data/arrow';
const t = binary(); // { kind: 'binary', typeId: 4 }
Properties
kind: 'binary'
typeId: 4
interface LargeBinaryType extends BaseType {
Variable-length byte string with 64-bit offsets, for columns whose data
may exceed the 2 GiB limit of BinaryType.
import { largeBinary } from 'fino:data/arrow';
const t = largeBinary(); // { kind: 'largebinary', typeId: 19 }
Properties
kind: 'largebinary'
typeId: 19
interface Utf8ViewType extends BaseType {
UTF-8 string in the view ("German string") layout: each value is a 16-byte view that inlines strings of 12 bytes or fewer and otherwise points into one of a variadic set of data buffers. Views make take/filter cheap because only the fixed-size view buffer is rewritten.
import { utf8View, hasVariadicBuffers } from 'fino:data/arrow';
hasVariadicBuffers(utf8View()); // true
Properties
kind: 'utf8view'
typeId: 24
interface BinaryViewType extends BaseType {
Byte string in the view layout: 16-byte views with short values inlined
and long values referencing variadic data buffers. The binary counterpart
of Utf8ViewType.
import { binaryView, bufferLayout } from 'fino:data/arrow';
bufferLayout(binaryView()); // ['validity', 'views']
Properties
kind: 'binaryview'
typeId: 23
interface FixedSizeBinaryType extends BaseType {
Byte string of exactly byteWidth bytes per value, stored contiguously
with no offsets buffer. Common for hashes, UUIDs, and fixed-size codes.
import { fixedSizeBinary } from 'fino:data/arrow';
const uuid = fixedSizeBinary(16);
Properties
kind: 'fixedsizebinary'
typeId: 15
byteWidth: number
Exact size of every value in bytes.
interface ListType extends BaseType {
Variable-length list with 32-bit offsets. The element type, name, and
nullability come from the child field.
import { list, int32, Field } from 'fino:data/arrow';
const scores = list(new Field('item', int32()));
Properties
kind: 'list'
typeId: 12
child: Field
Element field: type, name, and nullability of list items.
interface LargeListType extends BaseType {
Variable-length list with 64-bit offsets, for lists whose flattened
element count may exceed the 32-bit range of ListType.
import { largeList, utf8, Field } from 'fino:data/arrow';
const t = largeList(new Field('item', utf8()));
Properties
kind: 'largelist'
typeId: 21
child: Field
Element field: type, name, and nullability of list items.
interface ListViewType extends BaseType {
List in the view layout: separate 32-bit offsets and sizes buffers, so lists may be stored out of order or share element ranges.
import { listView, int32, Field, bufferLayout } from 'fino:data/arrow';
const t = listView(new Field('item', int32()));
bufferLayout(t); // ['validity', 'offset32', 'size32']
Properties
kind: 'listview'
typeId: 25
child: Field
Element field: type, name, and nullability of list items.
interface LargeListViewType extends BaseType {
List in the view layout with 64-bit offsets and sizes; the large-offset
counterpart of ListViewType.
import { largeListView, int32, Field } from 'fino:data/arrow';
const t = largeListView(new Field('item', int32()));
Properties
kind: 'largelistview'
typeId: 26
child: Field
Element field: type, name, and nullability of list items.
interface FixedSizeListType extends BaseType {
List of exactly listSize elements per value. No offsets buffer is
needed; element i of list j lives at child index j * listSize + i.
import { fixedSizeList, float32, Field } from 'fino:data/arrow';
const vec3 = fixedSizeList(3, new Field('item', float32(), false));
Properties
kind: 'fixedsizelist'
typeId: 16
listSize: number
Exact number of elements in every list value.
child: Field
Element field: type, name, and nullability of list items.
interface StructType extends BaseType {
Named tuple of child columns. The struct itself only carries a validity bitmap; each child field stores its own buffers at the same length.
import { struct, int32, utf8, Field } from 'fino:data/arrow';
const person = struct([
new Field('name', utf8(), false),
new Field('age', int32()),
]);
Properties
kind: 'struct'
typeId: 13
children: Field[]
Member fields, in declaration order.
interface MapType extends BaseType {
Map from keys to values, physically a list of entries structs. The
child field must be a non-nullable struct with a non-nullable key field
and a value field. keysSorted asserts keys are sorted within each map.
import { map, struct, utf8, int32, Field } from 'fino:data/arrow';
const entries = new Field('entries', struct([
new Field('key', utf8(), false),
new Field('value', int32()),
]), false);
const t = map(entries);
Properties
kind: 'map'
typeId: 17
keysSorted: boolean
Whether keys are sorted within each individual map value.
child: Field
The entries struct field holding key and value children.
interface UnionType extends BaseType {
Tagged union of child types. Each slot's typeIds-buffer entry selects a
child; typeIds[i] gives the tag value for child i. In Dense mode an
extra 32-bit offsets buffer indexes into per-child columns; in Sparse
mode every child spans the full length.
import { union, UnionMode, int32, utf8, Field } from 'fino:data/arrow';
const t = union(UnionMode.Dense, [0, 1], [
new Field('num', int32()),
new Field('str', utf8()),
]);
Properties
kind: 'union'
typeId: 14
mode: number
One of the UnionMode constants: Sparse or Dense.
typeIds: number[]
Tag value stored in the typeIds buffer for each child, by child index.
children: Field[]
Child fields, one per union variant.
interface DictionaryType extends BaseType {
Dictionary-encoded column: values are indices of indexType into a shared
dictionary of valueType values. Following Arrow convention, typeId
mirrors the value type's id — dictionary encoding is a physical encoding
recorded on the field, not a distinct logical type — so always check
kind === 'dictionary' rather than the numeric id.
import { dictionary, int8, utf8 } from 'fino:data/arrow';
// Low-cardinality strings: int8 codes into a utf8 dictionary.
const color = dictionary(0, int8(), utf8());
Properties
kind: 'dictionary'
typeId: number
id: number
Dictionary id linking the field to its dictionary batch in IPC.
indexType: IntType
Integer type of the index (code) values.
valueType: DataType
Logical type of the dictionary's values.
isOrdered: boolean
Whether dictionary order is semantically meaningful.
interface RunEndEncodedType extends BaseType {
Run-end encoded column: the runEnds child holds the exclusive end index
of each run and the values child holds one value per run. The type
itself has no buffers — all data lives in the two children.
import { runEndEncoded, int32, utf8, Field } from 'fino:data/arrow';
const t = runEndEncoded(
new Field('run_ends', int32(), false),
new Field('values', utf8()),
);
Properties
kind: 'runendencoded'
typeId: 22
runEnds: Field
Field of run end indices; must be a non-nullable integer field.
values: Field
Field holding one value per run.
interface VectorData {
Raw column data used to construct a Vector via makeVector.
Only the buffers relevant to the layout of type are consulted; the rest
may be omitted. Buffers are raw little-endian bytes (Uint8Array) exactly
as they appear in Arrow IPC — e.g. valueOffsets for a utf8 column is
the byte image of an Int32Array, not the typed array itself.
import { makeVector, int32 } from 'fino:data/arrow';
const values = new Uint8Array(new Int32Array([10, 20, 30]).buffer);
const v = makeVector({ type: int32(), length: 3, values });
v.get(2); // 30
Properties
type: DataType
Logical type of the column; its kind selects the physical layout.
length: number
Number of logical elements.
nullCount?: number
Known null count. Omit (or pass a negative value) to have it computed
lazily from validity on first access.
validity?: Uint8Array | null
Validity bitmap, LSB-first (bit set = valid). null or omitted means
every value is valid.
offset?: number
Logical element offset into the buffers. Non-zero for zero-copy slices and for data imported with an offset (e.g. via the C Data Interface).
values?: Uint8Array
Primary data buffer: fixed-width values, variable-length data bytes, bit-packed booleans, or dictionary indices, depending on the layout.
valueOffsets?: Uint8Array
Offsets buffer for variable-length binary/utf8, list, and map layouts
(i32, or i64 for the large* variants), and for dense unions.
sizes?: Uint8Array
Sizes buffer for the listview/largelistview layouts.
views?: Uint8Array
16-byte view structs for the utf8view/binaryview layouts.
variadicBuffers?: Uint8Array[]
Data buffers referenced by views entries longer than 12 bytes.
typeIds?: Uint8Array
Per-slot child type ids for union layouts.
children?: Vector[]
Child vectors for nested layouts (list, struct, map, union, run-end).
dictionary?: Vector
Decoded values vector for dictionary layouts; values then holds the
indices.
interface IPCWriteOptions {
Options controlling IPC serialization.
Accepted by every writer in this module. Compression applies to record batch and dictionary batch bodies only — message metadata is never compressed — and readers on the other end must support the chosen codec.
import { RecordBatch, tableToIPC, type IPCWriteOptions } from 'fino:data/arrow';
const options: IPCWriteOptions = { compression: 'lz4' };
const bytes = tableToIPC(RecordBatch.from({ id: [1, 2, 3] }), options);
Properties
compression?: 'lz4' | 'zstd'
Body compression codec, or undefined for uncompressed buffers.
'lz4' is the LZ4 frame format; 'zstd' is Zstandard. The codec must be
available through fino:compress (backed by the system's liblz4 /
libzstd). Buffers that do not shrink under compression are stored raw,
so enabling compression never inflates a body buffer beyond its 8-byte
length prefix.
Functions
function fixedWidthBytes(type: DataType): number
Byte size of a fixed-width type's element, or 0 for variable-width types.
Note that bool also reports 0: values are bit-packed, so no whole-byte
element size exists. Nested and variable-length types (lists, structs,
strings, views) all return 0.
import { fixedWidthBytes, int64, utf8, bool } from 'fino:data/arrow';
fixedWidthBytes(int64()); // 8
fixedWidthBytes(utf8()); // 0 (variable width)
fixedWidthBytes(bool()); // 0 (bit-packed)
function bufferLayout(type: DataType): BufferKind[]
The physical buffer layout of a type, in Arrow pre-order. Does not include child-column buffers (those follow the parent's own node in IPC order).
Dictionary types report the layout of their index type, since only the
codes live in the column itself. Null and run-end-encoded types own no
buffers and return an empty array. View types report views but not
their variadic data buffers — check hasVariadicBuffers for those.
import { bufferLayout, utf8, list, int32, Field } from 'fino:data/arrow';
bufferLayout(utf8()); // ['validity', 'offset32', 'data']
bufferLayout(list(new Field('item', int32()))); // ['validity', 'offset32']
function childFields(type: DataType): Field[]
Child fields of a nested type, in Arrow order. Empty for leaf types.
Run-end-encoded types return [runEnds, values]; dictionaries return
nothing here because the dictionary column travels separately.
import { childFields, struct, int32, Field } from 'fino:data/arrow';
const t = struct([new Field('x', int32(), false)]);
childFields(t).map((f) => f.name); // ['x']
function hasVariadicBuffers(type: DataType): boolean
Whether a type carries variadic data buffers (the View types).
IPC record batches list a per-column buffer count; view columns append a variable number of data buffers after the fixed layout, so writers and readers use this to know when to expect them.
import { hasVariadicBuffers, utf8View, utf8 } from 'fino:data/arrow';
hasVariadicBuffers(utf8View()); // true
hasVariadicBuffers(utf8()); // false
function formatType(type: DataType): string
A human-readable label for error messages. Currently the kind string.
import { formatType, timestamp } from 'fino:data/arrow';
throw new Error(`unsupported type: ${formatType(timestamp())}`);
function typeEquals(a: DataType, b: DataType): boolean
Structural equality of two types.
Compares every own parameter (bit width, unit, timezone, precision, ...)
and recurses through child fields, requiring matching child names and
nullability as well as equal child types. Dictionary types additionally
compare index and value types, though the dictionary id and other
non-child parameters must also match.
import { typeEquals, timestamp, TimeUnit } from 'fino:data/arrow';
typeEquals(timestamp(TimeUnit.MICROSECOND, 'UTC'),
timestamp(TimeUnit.MICROSECOND, 'UTC')); // true
typeEquals(timestamp(TimeUnit.MICROSECOND, 'UTC'),
timestamp(TimeUnit.MICROSECOND, null)); // false
function makeVector(data: VectorData): Vector
Construct a vector from raw column buffers.
Selects the layout subclass from data.type.kind and wraps the provided
buffers without copying. This is the hot path used by IPC decoding and
native producers, so no validation is performed — buffers are trusted to
match the layout of type, and missing or undersized buffers surface as
errors (or garbage reads) only when elements are accessed.
import { makeVector, vectorFromArray, dictionary, int8, utf8 } from 'fino:data/arrow';
// A dictionary-encoded column: int8 indices into ['red', 'green', 'blue'].
const v = makeVector({
type: dictionary(0, int8(), utf8()),
length: 4,
values: new Uint8Array([0, 1, 0, 2]),
dictionary: vectorFromArray(['red', 'green', 'blue'], utf8()),
});
v.toArray(); // ['red', 'green', 'red', 'blue']
function vectorFromArray(values: unknown[], type?: DataType): Vector
Build a vector from plain JS values, inferring the type when not given.
Inference looks at the first non-null value: boolean → bool, number →
float64, bigint → int64, string → utf8, arrays → list, other objects →
struct. An all-null input infers int32. Passing an explicit type skips
inference and encodes the values for that layout — supported kinds are
bool, the fixed-width primitives (int, float, date, time, timestamp,
duration), utf8/binary and their large* variants, list/largelist, struct,
map, decimal, and fixedsizebinary. Both null and undefined become null
slots.
Throws ArrowError for kinds it cannot build (views, unions,
dictionaries, run-end encoding, intervals, fixed-size lists) — construct
those with makeVector from raw buffers instead.
Intended for convenience and tests; makeVector is the performance path.
import { vectorFromArray, timestamp, TimeUnit } from 'fino:data/arrow';
vectorFromArray(['a', null, 'c']).toArray(); // ['a', null, 'c']
vectorFromArray([{ x: 1 }, { x: 2 }]).get(1); // { x: 2 }
const ts = vectorFromArray([1720000000000n, null], timestamp(TimeUnit.MILLISECOND));
ts.get(0); // 1720000000000n
function tableFromIPC(bytes: Uint8Array | ArrayBuffer): Table
Decode an Arrow IPC buffer (stream or file format) into a Table.
The one-call counterpart to tableToIPC: format detection, dictionary
resolution, and decompression all happen internally. Equivalent to
RecordBatchReader.from(bytes).toTable(); use the reader classes directly
when per-batch access matters. Throws ArrowParseError on malformed input
or when no schema message is present.
import { tableFromIPC, tableToIPC, RecordBatch } from 'fino:data/arrow';
const bytes = tableToIPC(RecordBatch.from({ id: [1, 2, 3] }));
const table = tableFromIPC(bytes);
console.log(table.numRows); // 3
function tableToIPC(source: Table | RecordBatch, options?: IPCWriteOptions & {
format?: 'stream' | 'file';
}): Uint8Array
Serialize a table or a single record batch to Arrow IPC bytes.
One-shot convenience over the writer classes: a Table writes each of its
batches in order, a lone RecordBatch writes just itself. format
selects the streaming format (the default) or the random-access file
format; tableFromIPC is the inverse and auto-detects which one it was
given. Throws ArrowError if the source contains no batches.
import { RecordBatch, Table, tableToIPC, tableFromIPC } from 'fino:data/arrow';
const b1 = RecordBatch.from({ id: [1, 2], name: ['a', 'b'] });
const b2 = RecordBatch.from({ id: [3, 4], name: ['c', 'd'] });
const bytes = tableToIPC(Table.from([b1, b2]), { format: 'file' });
tableFromIPC(bytes).numRows; // 4
Classes
class Field {
A named, nullable column type with optional key/value metadata.
Fields compose recursively to describe nested types: list, fixedSizeList,
map, union, and runEndEncoded types each carry child fields, and
struct carries one field per member. nullable defaults to true,
matching Arrow's convention that a column admits nulls unless declared
otherwise.
Instances are immutable — to "change" a field, construct a new one.
import { Field, list, float64, struct, utf8 } from 'fino:data/arrow';
const readings = new Field('readings', list(new Field('item', float64(), false)));
const meta = new Field('meta', struct([new Field('tag', utf8())]), true,
new Map([['origin', 'sensor-7']]));
Readonly Properties
readonly name: string
Column (or nested child) name as it appears in the schema.
readonly type: DataType
Logical Arrow type of the field's values.
readonly nullable: boolean
Whether the field is declared to admit nulls. Carried through IPC metadata and the C Data Interface flags, but never enforced against actual column data.
readonly metadata: Map<string, string> | null
Field-level key/value metadata, or null when absent. Stored by reference
and serialized alongside the field in Arrow IPC.
Constructors
constructor(
name: string,
type: DataType,
nullable = true,
metadata: Map<string, string> | null = null
)
Static Methods
static new(
name: string,
type: DataType,
nullable = true,
metadata?: Map<string, string> | null
): Field
Build a field; a convenience mirror of the constructor that also accepts
undefined metadata (normalized to null).
class Schema {
An ordered list of fields plus schema-level metadata: the type of a
RecordBatch or Table.
Column order is significant — the vectors of a RecordBatch align
positionally with fields. The constructor performs no validation:
duplicate field names are permitted, and field() simply returns the first
match.
import { Schema, Field, int32, utf8 } from 'fino:data/arrow';
const inferred = Schema.from({ id: int32(), name: utf8() });
const strict = new Schema(
[new Field('id', int32(), false), new Field('name', utf8())],
new Map([['version', '2']]),
);
strict.field('id')?.nullable; // false
Readonly Properties
readonly fields: Field[]
Top-level fields, in column order.
readonly metadata: Map<string, string> | null
Schema-level key/value metadata, or null when absent. Stored by
reference and serialized with the schema in Arrow IPC.
Constructors
constructor(fields: Field[], metadata: Map<string, string> | null = null)
Static Methods
static from(
fields: Field[] | Record<string, DataType>,
metadata?: Map<string, string> | null
): Schema
Build a schema from an array of fields, or from a { name: type } record
for the common all-nullable case.
With the record form, property insertion order becomes column order, every
field is nullable, and no per-field metadata is attached — pass Field
instances instead when any of those need control.
import { Schema, int64, utf8, float64 } from 'fino:data/arrow';
const schema = Schema.from({ id: int64(), name: utf8(), score: float64() });
schema.fields.map((f) => f.name); // ['id', 'name', 'score']
Methods
field(name: string): Field | undefined
Look up a top-level field by name, returning undefined when no field
matches. Does not descend into the children of nested types.
abstract class Vector {
Abstract base for every Arrow vector — one typed, immutable column.
The concrete subclasses (one per physical layout) are private; obtain
instances through makeVector, vectorFromArray, or by decoding IPC data.
All element access flows through get, which applies the validity bitmap
and the logical offset before dispatching to the layout-specific read.
Vectors are iterable, yielding get(0) through get(length - 1).
import { vectorFromArray } from 'fino:data/arrow';
const v = vectorFromArray([1.5, null, 3]); // inferred float64
v.isValid(1); // false
v.get(2); // 3
[...v]; // [1.5, null, 3]
Readonly Properties
readonly type: DataType
Logical type of the column.
readonly length: number
Number of logical elements.
Constructors
constructor(data: VectorData)
Getters
get nullCount(): number
Number of null entries (computed lazily from the validity bitmap).
Methods
isValid(i: number): boolean
Whether element i is non-null.
get(i: number): unknown
Read element i, returning the physical value, or null for a null
slot. Out-of-range indices return undefined.
toArray(): unknown[]
Materialize the column as a plain array (nulls become null).
slice(begin = 0, end: number = this.length): Vector
A zero-copy logical sub-range of this vector.
The result shares the underlying buffers; only the logical offset and
length change. end is exclusive and clamped to the vector length;
negative indices are not supported. The null count of the slice is
recomputed lazily for the new range.
class RecordBatch {
A batch of equal-length columns described by a Schema.
Construct directly when the schema and typed vectors are already in hand
(the IPC reader and C Data importer do this), or use RecordBatch.from to
build one from plain JS arrays with inferred types. All fields are
read-only after construction.
import { RecordBatch, Schema, vectorFromArray, int32, utf8 } from 'fino:data/arrow';
const batch = new RecordBatch(
Schema.from({ id: int32(), name: utf8() }),
[vectorFromArray([1, 2], int32()), vectorFromArray(['a', 'b'], utf8())],
);
batch.row(0); // { id: 1, name: 'a' }
Readonly Properties
readonly schema: Schema
Column schema; schema.fields[i] describes columns[i].
readonly columns: Vector[]
Column vectors, aligned with schema.fields.
readonly numRows: number
Row count shared by every column (0 for a zero-column batch).
Constructors
constructor(schema: Schema, columns: Vector[])
Pair schema with columns.
Throws ArrowError if the number of columns differs from the number of
schema fields, or if the columns are not all the same length.
Static Methods
static from(input: Record<string, unknown[]> | {
schema: Schema;
columns: Vector[];
}): RecordBatch
Build a record batch from { name: values[] } (types inferred) or from an
explicit { schema, columns } pair.
In the record form each entry becomes one column via vectorFromArray:
JS numbers infer Float64, bigints Int64, strings Utf8, booleans
Bool, arrays List, and plain objects Struct. A field is marked nullable
only when its values actually contain null or undefined. When the
inferred types are not what a consumer expects — integer ids that should
be Int32 rather than Float64, say — build the vectors explicitly and pass
the { schema, columns } form instead.
import { RecordBatch } from 'fino:data/arrow';
const batch = RecordBatch.from({
id: [1n, 2n, 3n], // bigint → Int64
name: ['ada', 'lin', null], // string → Utf8, marked nullable
});
batch.schema.fields.map((f) => f.type.kind); // ['int', 'utf8']
Getters
get numColumns(): number
Number of columns.
Methods
getChild(name: string): Vector | undefined
Column vector for the first field named name, or undefined when no
such field exists.
columnAt(i: number): Vector | undefined
Column vector at position i, or undefined when out of range.
row(i: number): Record<string, unknown>
Materialize row i as a plain object keyed by field name.
Builds a fresh object on every call; for bulk numeric work prefer
getChild and column-wise access.
toArray(): Record<string, unknown>[]
All rows as plain objects; equivalent to spreading the batch.
slice(begin = 0, end: number = this.numRows): RecordBatch
A zero-copy row sub-range: the returned batch shares column buffers with
this one. end is exclusive and clamped to numRows; negative indices
are not supported.
class Table {
A schema plus zero or more equally-shaped record batches.
The table is a thin view over its batches: nothing is copied, and batches
keep their identity (batches is the array passed in). Row iteration
and toArray walk the batches in order, yielding each row as a plain
{ name: value } object of raw physical values. Column access via
getChild/columnAt returns chunked Column views instead of flattened
arrays, so a multi-gigabyte IPC stream can be scanned without
re-materializing its columns.
Throws if any batch's column count differs from the table schema's field count; deeper type agreement between batches is the producer's responsibility.
import { RecordBatch, Table, tableFromIPC } from 'fino:data/arrow';
// From batches produced locally...
const table = Table.from([
RecordBatch.from({ id: [1, 2], name: ['ada', 'grace'] }),
RecordBatch.from({ id: [3], name: ['edsger'] }),
]);
// ...or from Arrow IPC bytes (pyarrow, polars, DuckDB, ...).
// const table = tableFromIPC(bytes);
table.numRows; // 3
table.getChild('name')!.get(2); // 'edsger'
for (const row of table) {
console.log(row.id, row.name);
}
Readonly Properties
readonly schema: Schema
Table schema.
readonly batches: RecordBatch[]
Constituent batches (chunks).
readonly numRows: number
Total row count across batches.
Constructors
constructor(schema: Schema, batches: RecordBatch[])
Wrap batches under schema.
Throws if a batch's schema has a different number of fields than
schema. An empty batch list is allowed and yields a zero-row table.
Static Methods
static from(batches: RecordBatch[]): Table
Build a table from batches, taking the schema from the first batch.
Throws if batches is empty — use the constructor with an explicit
schema to represent a zero-batch table.
Getters
get numColumns(): number
Number of columns.
Methods
getChild(name: string): Column | undefined
A chunked Column view over the named field, or undefined when no
top-level field has that name. Each call builds a fresh view.
columnAt(i: number): Column
A chunked Column view over the field at position i. The position must
be within [0, numColumns); it is not range-checked.
toArray(): Record<string, unknown>[]
Materialize all rows as plain objects across batches, in row order.
class Column {
A logical column spanning a table's batches, addressed as one sequence.
A column never copies data: it holds one Vector chunk per batch and
translates a table-wide row index into a (chunk, local index) pair on each
access. Columns are produced by Table.getChild and Table.columnAt; each
call builds a fresh view over the table's batches.
Values come back as the underlying vectors' raw physical values: null for
nulls, number for widths up to 32 bits, bigint for 64-bit integers and
timestamps, string, Uint8Array for binary, and arrays/objects for
nested types.
import { RecordBatch, Table } from 'fino:data/arrow';
const table = Table.from([
RecordBatch.from({ n: [1, 2] }),
RecordBatch.from({ n: [3, 4, 5] }),
]);
const col = table.getChild('n')!;
col.length; // 5
col.get(3); // 4 — crosses the chunk boundary transparently
[...col]; // [1, 2, 3, 4, 5]
Readonly Properties
readonly length: number
Total element count across chunks.
Constructors
constructor(chunks: Vector[])
Wrap per-batch chunk vectors as one logical sequence.
Methods
get(i: number): unknown
Read element i across chunk boundaries.
A cached cursor remembers which chunk served the previous read, so
sequential scans resolve their chunk in constant time; a read outside the
cached chunk falls back to a linear search from the first chunk. Indices
outside [0, length) are not range-checked.
toArray(): unknown[]
Materialize the whole column as a plain array, in row order.
class ArrowError extends Error {
Error thrown for invalid Arrow usage: bad buffer lengths, unsupported types passed to a builder, or malformed values.
This is the "caller error" class — it signals a problem with the arguments
or data handed to the Arrow API rather than with decoded bytes. Typical
sources: constructing a RecordBatch whose columns differ in length or
count from the schema, combining batches with mismatched schemas into a
Table, asking vectorFromArray to build an unsupported type, or writing
a sliced column through the IPC writer. Decoding failures throw
ArrowParseError instead.
import { ArrowError, RecordBatch, Schema, Field, int32, vectorFromArray } from 'fino:data/arrow';
const schema = new Schema([new Field('a', int32()), new Field('b', int32())]);
try {
new RecordBatch(schema, [vectorFromArray([1, 2, 3], int32())]);
} catch (err) {
err instanceof ArrowError; // true: 2 fields, 1 column
}
class ArrowParseError extends ParseError {
Error thrown when decoding an Arrow IPC stream or file that is malformed or
uses an unsupported feature. Extends ParseError for hex-dump diagnostics.
Raised by tableFromIPC, RecordBatchReader, and RecordBatchFileReader
for truncated buffers, missing magic bytes or continuation markers, streams
with no schema message, and legacy pre-0.15 encapsulated messages. The
inherited offset property locates the failing byte in the input, and
render() formats a hex dump around it for logging.
import { ArrowParseError, tableFromIPC } from 'fino:data/arrow';
try {
tableFromIPC(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
} catch (err) {
if (err instanceof ArrowParseError) {
console.error(`bad IPC data at byte ${err.offset}`);
console.error(err.render());
}
}
class RecordBatchReader {
Reads record batches from an Arrow IPC stream or file.
Construct via the static factories: from for in-memory bytes, fromAsync
for an async byte source. Both formats are detected automatically — a
buffer starting with the ARROW1 magic is treated as a file, anything else
as a stream. All batches are decoded eagerly at construction; the instance
is a plain container afterwards, iterable batch by batch or collapsible
into a Table.
Construction throws ArrowParseError when the input holds no schema
message or uses the legacy pre-0.15 framing, and ArrowError when a
dictionary-encoded column references a dictionary that never arrived or a
delta dictionary batch is encountered.
import { RecordBatchReader } from 'fino:data/arrow';
const reader = RecordBatchReader.from(bytes);
console.log(reader.schema.fields.map((f) => f.name));
for (const batch of reader) {
console.log(batch.numRows);
}
Readonly Properties
readonly schema: Schema
The schema shared by every batch, from the stream's schema message.
readonly batches: RecordBatch[]
All decoded batches, in stream order.
Static Methods
static from(bytes: Uint8Array | ArrayBuffer): RecordBatchReader
Read all batches from an in-memory Arrow IPC buffer, in either stream or file format.
Decoded vectors alias the input where the body is uncompressed, so keep
the buffer intact for as long as the batches are used. Throws
ArrowParseError if the bytes contain no schema message or cannot be
parsed.
static async fromAsync(source: AsyncIterable<Uint8Array> | {
read(): Promise<Uint8Array | null>;
}): Promise<RecordBatchReader>
Read all batches from an async byte source.
Accepts anything async-iterable over Uint8Array chunks, or an object
with a read() method that resolves chunks until null. The entire
source is buffered into memory first, then parsed exactly like from —
this is a convenience for sockets and file readers, not a bounded-memory
streaming decoder.
import { RecordBatchReader } from 'fino:data/arrow';
import { DiskFileSystem } from 'fino:file';
const fs = new DiskFileSystem();
const file = await fs.open('/data/events.arrows');
const reader = await RecordBatchReader.fromAsync(file.reader());
await file.close();
Methods
toTable(): Table
Collect all batches into a Table sharing this reader's schema.
class RecordBatchFileReader {
Reader for the Arrow IPC file format with indexed batch access.
Unlike RecordBatchReader, construction insists on the ARROW1 magic and
throws ArrowParseError if it is absent — use this class when the input
must be a well-formed Arrow file rather than a bare stream. All batches are
decoded eagerly (the footer only bounds the message scan), after which
batch(i) and numBatches give positional access.
import { RecordBatchFileReader } from 'fino:data/arrow';
const reader = RecordBatchFileReader.from(bytes);
const last = reader.batch(reader.numBatches - 1);
console.log(last.numRows);
Readonly Properties
readonly schema: Schema
The schema shared by every batch, from the file's schema message.
readonly batches: RecordBatch[]
All decoded batches, in file order.
Static Methods
static from(bytes: Uint8Array | ArrayBuffer): RecordBatchFileReader
Read an Arrow IPC file buffer.
Throws ArrowParseError if the buffer does not start with the ARROW1
magic, contains no schema message, or cannot be parsed. Uncompressed
vector buffers alias the input bytes, so do not mutate them while the
decoded batches are in use.
Getters
get numBatches(): number
Number of record batches in the file.
Methods
batch(i: number): RecordBatch
The batch at index i, in file order.
Throws ArrowError when i is outside 0..numBatches - 1.
toTable(): Table
Collect all batches into a Table sharing this reader's schema.
class RecordBatchStreamWriter {
Writer for the Arrow IPC streaming format.
Produces the sequential wire form — schema message, dictionary batches,
record batches, end-of-stream marker — meant for transports where the
consumer reads messages in order (sockets, pipes, HTTP bodies) and for any
Arrow-speaking peer (pyarrow, polars, DuckDB, ...). The schema is taken
from the first batch written; later batches are assumed to match it and
are not validated. The whole stream is buffered in memory until toBytes.
import { RecordBatch, RecordBatchStreamWriter } from 'fino:data/arrow';
const writer = new RecordBatchStreamWriter({ compression: 'lz4' });
writer
.write(RecordBatch.from({ id: [1, 2], name: ['a', 'b'] }))
.write(RecordBatch.from({ id: [3, 4], name: ['c', 'd'] }));
const bytes = writer.toBytes();
Constructors
constructor(options?: IPCWriteOptions)
Create a stream writer, optionally compressing batch bodies.
Methods
write(batch: RecordBatch): this
Append a batch; returns this so calls chain.
Throws ArrowError for sliced list-view, union, or run-end-encoded
columns, which must be compacted before writing.
toBytes(): Uint8Array
Finish the stream and return the full byte buffer.
Appends the end-of-stream marker, so nothing more can be written. Throws
ArrowError if no batch was written. Call exactly once.
class RecordBatchFileWriter {
Writer for the Arrow IPC file format (also known as Feather V2).
Wraps the streaming message sequence in ARROW1 magic bytes and appends a
Flatbuffers footer recording the offset and size of every dictionary and
record batch block, so readers can seek straight to any batch without
scanning. This is the format to persist to disk (conventionally .arrow
files); use RecordBatchStreamWriter for sequential transports. Like the
stream writer, the schema comes from the first batch and everything is
buffered in memory until toBytes.
import { RecordBatch, RecordBatchFileWriter } from 'fino:data/arrow';
const writer = new RecordBatchFileWriter({ compression: 'zstd' });
writer.write(RecordBatch.from({ id: [1, 2, 3], score: [0.5, 0.9, 0.1] }));
const bytes = writer.toBytes(); // write these to a .arrow file
Constructors
constructor(options?: IPCWriteOptions)
Create a file writer, optionally compressing batch bodies.
Methods
write(batch: RecordBatch): this
Append a batch; returns this so calls chain.
Throws ArrowError for sliced list-view, union, or run-end-encoded
columns, which must be compacted before writing.
toBytes(): Uint8Array
Finish the file and return the full byte buffer.
Appends the footer and trailing magic, so nothing more can be written.
Throws ArrowError if no batch was written. Call exactly once.