blob: f95d12f04397b5657f8ed43452af3c12b815be80 [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.
*/
/* This file is based on source code from the Spark Project (http://spark.apache.org/), licensed
* by the Apache Software Foundation (ASF) under the Apache License, Version 2.0. See the NOTICE
* file distributed with this work for additional information regarding copyright ownership. */
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include "paimon/common/data/variant/variant_binary_util.h"
#include "paimon/memory/bytes.h"
#include "paimon/memory/memory_pool.h"
#include "paimon/result.h"
namespace paimon {
/// A Variant represents a type that contains one of: 1) Primitive: A type and corresponding value
/// (e.g. INT, STRING); 2) Array: An ordered list of Variant values; 3) Object: An unordered
/// collection of string/Variant pairs (i.e. key/value pairs). An object may not contain duplicate
/// keys.
///
/// A Variant is encoded with 2 binaries: the value and the metadata. The Variant Binary Encoding
/// allows representation of semi-structured data (e.g. JSON) in a form that can be efficiently
/// queried by path. The design is intended to allow efficient access to nested data even in the
/// presence of very wide or deep structures.
class GenericVariant {
public:
/// A field of a variant object.
struct ObjectField {
std::string key;
std::shared_ptr<GenericVariant> value;
};
/// Creates a variant taking ownership of the given buffers. Fails with `MALFORMED_VARIANT`
/// if the metadata version is unsupported, or `VARIANT_CONSTRUCTOR_SIZE_LIMIT` if either
/// buffer exceeds the 128MiB size limit.
static Result<std::shared_ptr<GenericVariant>> Create(std::shared_ptr<Bytes> value,
std::shared_ptr<Bytes> metadata);
/// Creates a variant by copying the given buffers into `pool`.
static Result<std::shared_ptr<GenericVariant>> Create(std::string_view value,
std::string_view metadata,
const std::shared_ptr<MemoryPool>& pool);
/// Parses a JSON string as a variant (duplicate object keys are rejected).
static Result<std::shared_ptr<GenericVariant>> FromJson(
std::string_view json, const std::shared_ptr<MemoryPool>& pool);
/// The variant value binary. For a sub-variant (`Pos() != 0`), the view covers only the
/// sub-variant slice of the underlying buffer.
Result<std::string_view> Value() const;
/// The whole underlying value buffer, regardless of `Pos()`.
std::string_view RawValue() const;
/// The variant metadata binary.
std::string_view Metadata() const;
/// The variant value doesn't use the whole value binary, but starts from the `Pos()` index
/// and spans a size of `VariantBinaryUtil::ValueSize`. This design avoids frequent copies of
/// the value binary when reading a sub-variant in an array/object element.
int32_t Pos() const {
return pos_;
}
/// The size of the variant in bytes (value size + metadata size).
int64_t SizeInBytes() const;
/// Stringifies the variant in JSON format. `zone_id` controls the rendering of TIMESTAMP
/// values; supported forms are "UTC"/"Z"/"GMT" and fixed offsets such as "+08:00".
Result<std::string> ToJson(const std::string& zone_id = "UTC") const;
/// The value type of the variant.
Result<VariantValueType> GetType() const;
/// The type info bits of the variant value header.
Result<int32_t> GetTypeInfo() const;
Result<bool> GetBoolean() const;
Result<int64_t> GetLong() const;
Result<double> GetDouble() const;
Result<VariantDecimal> GetDecimal() const;
Result<float> GetFloat() const;
Result<std::string_view> GetBinary() const;
Result<std::string_view> GetString() const;
/// The 16-byte big-endian UUID value.
Result<std::string_view> GetUuid() const;
/// The number of object fields in the variant. It is only legal to call it when `GetType()`
/// is `kObject`.
Result<int32_t> ObjectSize() const;
/// Finds the field value whose key is equal to `key`. Returns nullptr if the key is not
/// found. It is only legal to call it when `GetType()` is `kObject`. The returned sub-variant
/// shares the underlying buffers with this variant.
Result<std::shared_ptr<GenericVariant>> GetFieldByKey(std::string_view key) const;
/// Gets the object field at the `index` slot. Returns nullopt if `index` is out of the bound
/// of `[0, ObjectSize())`. It is only legal to call it when `GetType()` is `kObject`.
Result<std::optional<ObjectField>> GetFieldAtIndex(int32_t index) const;
/// Gets the metadata dictionary id for the object field at the `index` slot. It is only
/// legal to call it when `GetType()` is `kObject`.
Result<int32_t> GetDictionaryIdAtIndex(int32_t index) const;
/// The number of array elements in the variant. It is only legal to call it when `GetType()`
/// is `kArray`.
Result<int32_t> ArraySize() const;
/// Gets the array element at the `index` slot. Returns nullptr if `index` is out of the
/// bound of `[0, ArraySize())`. It is only legal to call it when `GetType()` is `kArray`.
Result<std::shared_ptr<GenericVariant>> GetElementAtIndex(int32_t index) const;
bool operator==(const GenericVariant& other) const;
private:
GenericVariant(std::shared_ptr<Bytes> value, std::shared_ptr<Bytes> metadata, int32_t pos);
std::shared_ptr<GenericVariant> SubVariant(int32_t pos) const;
std::shared_ptr<Bytes> value_;
std::shared_ptr<Bytes> metadata_;
int32_t pos_;
};
} // namespace paimon