blob: db1b66f633f2c336c70615debfa85c2d2e19e7a4 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#pragma once
/// \file iceberg/arrow_row_builder_internal.h
/// Internal Arrow row-building utilities shared by metadata tables.
///
/// Metadata tables (snapshots, history, manifests, ...) materialize in-memory
/// structures into Arrow batches that conform to the table's Iceberg schema.
/// `ArrowRowBuilder` wraps a nanoarrow `ArrowArray` initialized from such a
/// schema and exposes per-column access plus typed append helpers so each
/// metadata table can emit rows without re-implementing the nanoarrow
/// boilerplate.
#include <cstdint>
#include <map>
#include <span>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "iceberg/arrow_c_data.h"
#include "iceberg/iceberg_export.h"
#include "iceberg/result.h"
#include "iceberg/type_fwd.h"
namespace iceberg {
/// \brief Movable RAII builder that materializes rows into an Arrow struct array.
///
/// Handles the nanoarrow lifecycle: InitFromSchema → StartAppending →
/// ... append values ... → FinishBuilding → Release.
///
/// Two constructors:
/// - `Make(schema)` accepts an Iceberg Schema (typical for metadata tables).
/// - `Make(arrow_schema)` accepts a raw ArrowSchema (for lower-level callers
/// like position_delete_writer or manifest_adapter).
///
/// Typical usage:
/// \code
/// ICEBERG_ASSIGN_OR_RAISE(auto builder, ArrowRowBuilder::Make(schema));
/// for (const auto& row : rows) {
/// ICEBERG_RETURN_UNEXPECTED(AppendInt(builder.column(0), row.id));
/// ICEBERG_RETURN_UNEXPECTED(AppendString(builder.column(1), row.name));
/// ICEBERG_RETURN_UNEXPECTED(builder.FinishRow());
/// }
/// ICEBERG_ASSIGN_OR_RAISE(auto array, std::move(builder).Finish());
/// \endcode
class ICEBERG_EXPORT ArrowRowBuilder {
public:
/// \brief Create a row builder from an Iceberg schema.
static Result<ArrowRowBuilder> Make(const Schema& schema);
/// \brief Create a row builder from an ArrowSchema.
///
/// The schema must outlive this call (the caller guards it). On failure the
/// partially-initialized array is released automatically.
static Result<ArrowRowBuilder> Make(const ArrowSchema* schema);
ArrowRowBuilder(ArrowRowBuilder&& other) noexcept;
ArrowRowBuilder& operator=(ArrowRowBuilder&& other) noexcept;
ArrowRowBuilder(const ArrowRowBuilder&) = delete;
ArrowRowBuilder& operator=(const ArrowRowBuilder&) = delete;
~ArrowRowBuilder();
/// \brief The number of top-level columns in the batch.
int64_t num_columns() const;
/// \brief Access the nanoarrow child builder for a top-level column.
///
/// \param index Zero-based column index. Returns nullptr if out of range.
ArrowArray* column(int64_t index);
/// \brief Finish the current row, advancing the struct length by one.
///
/// Call after appending exactly one value (or null) to every column.
Status FinishRow();
/// \brief Finish building and transfer ownership of the resulting array.
///
/// The builder must not be used after this call.
Result<ArrowArray> Finish() &&;
private:
ArrowRowBuilder() = default;
ArrowArray array_{};
};
/// \brief Append a null to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendNull(ArrowArray* array);
/// \brief Append a boolean value to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendBoolean(ArrowArray* array, bool value);
/// \brief Append an integer value to a nanoarrow array builder.
///
/// Works for int32/int64/timestamp columns, which nanoarrow stores as int64.
ICEBERG_EXPORT Status AppendInt(ArrowArray* array, int64_t value);
/// \brief Append an unsigned integer value to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendUInt(ArrowArray* array, uint64_t value);
/// \brief Append a double value to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendDouble(ArrowArray* array, double value);
/// \brief Append a string value to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendString(ArrowArray* array, std::string_view value);
/// \brief Append a binary value to a nanoarrow array builder.
ICEBERG_EXPORT Status AppendBytes(ArrowArray* array, std::span<const uint8_t> value);
/// \brief Append a list of int32 values to a nanoarrow list array builder.
ICEBERG_EXPORT Status AppendIntList(ArrowArray* array,
const std::vector<int32_t>& values);
/// \brief Append a list of int64 values to a nanoarrow list array builder.
ICEBERG_EXPORT Status AppendIntList(ArrowArray* array,
const std::vector<int64_t>& values);
/// \brief Append a map<string, string> value to a nanoarrow map array builder.
///
/// Appends one (possibly empty) map element. The iteration order of the
/// resulting entries is unspecified.
ICEBERG_EXPORT Status AppendStringMap(
ArrowArray* array, const std::unordered_map<std::string, std::string>& entries);
/// \brief Append a map<int32, int64> to a nanoarrow map array builder.
ICEBERG_EXPORT Status AppendIntMap(ArrowArray* array,
const std::map<int32_t, int64_t>& entries);
/// \brief Append a map<int32, binary> to a nanoarrow map array builder.
ICEBERG_EXPORT Status AppendBinaryMap(
ArrowArray* array, const std::map<int32_t, std::vector<uint8_t>>& entries);
} // namespace iceberg