// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0
// Turning a result handle into rows. The C API hands back a materialised result and the
// wasm build hands back a table of Arrow vectors; both are addressed the same way — a
// column index, a row index, and the cell's kind — so this file serves both backends.
///|
/// Every row of a result, then the result is released — the caller never holds an engine
/// handle it would have to close.
fn read_result(result : Int64) -> Array[@moondb.Row] raise @moondb.DbError {
if result == 0L {
raise error_of(bytes_to_str(ffi_error()))
}
let message = bytes_to_str(ffi_result_message(result))
if message != "" {
ffi_result_close(result)
raise error_of(message)
}
let cols = ffi_cols(result)
let names : Array[String] = []
for i = 0; i < cols; i = i + 1 {
names.push(bytes_to_str(ffi_col_name(result, i)))
}
let rows : Array[@moondb.Row] = []
let count = ffi_rows(result)
for r = 0L; r < count; r = r + 1 {
let values : Array[@moondb.Value] = []
for c = 0; c < cols; c = c + 1 {
values.push(cell(result, c, r))
}
rows.push({ columns: names, values, })
}
ffi_result_close(result)
rows
}
///|
/// One cell as the `Value` its column type implies. `NULL` is a case of its own, so a
/// column of nullable integers does not turn its missing values into zeros.
fn cell(result : Int64, col : Int32, row : Int64) -> @moondb.Value {
match ffi_cell_kind(result, col, row) {
0 => @moondb.Null
1 => @moondb.Int64(ffi_cell_int(result, col, row))
2 => @moondb.Double(ffi_cell_double(result, col, row))
3 => @moondb.Bool(ffi_cell_bool(result, col, row) != 0)
5 => @moondb.Blob(ffi_cell_blob(result, col, row))
_ => @moondb.Text(bytes_to_str(ffi_cell_text(result, col, row)))
}
}