| /* | |
| * 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/expression/term.h | |
| /// Term interface for Iceberg expressions - represents values that can be evaluated. | |
| #include <concepts> | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include "iceberg/expression/expression.h" | |
| #include "iceberg/expression/literal.h" | |
| #include "iceberg/type_fwd.h" | |
| #include "iceberg/util/formattable.h" | |
| namespace iceberg { | |
| /// \brief A term is an expression node that produces a typed value when evaluated. | |
| class ICEBERG_EXPORT Term : public util::Formattable { | |
| public: | |
| enum class Kind : uint8_t { kReference, kTransform, kExtract }; | |
| /// \brief Returns the kind of this term. | |
| virtual Kind kind() const = 0; | |
| /// \brief Returns whether this term is unbound. | |
| virtual bool is_unbound() const = 0; | |
| }; | |
| template <typename T> | |
| concept TermType = std::derived_from<T, Term>; | |
| /// \brief Base class for unbound terms. | |
| /// | |
| /// \tparam B The bound type this term produces when binding is successful. | |
| template <typename B> | |
| class ICEBERG_EXPORT UnboundTerm : public Unbound<B>, public Term { | |
| public: | |
| using BoundType = B; | |
| bool is_unbound() const override { return true; } | |
| }; | |
| /// \brief Base class for bound terms. | |
| class ICEBERG_EXPORT BoundTerm : public Bound, public Term { | |
| public: | |
| ~BoundTerm() override; | |
| /// \brief Returns the type produced by this term. | |
| virtual std::shared_ptr<Type> type() const = 0; | |
| /// \brief Returns whether this term may produce null values. | |
| virtual bool MayProduceNull() const = 0; | |
| /// \brief Returns whether this term is equivalent to another. | |
| /// | |
| /// Two terms are equivalent if they produce the same values when evaluated. | |
| /// | |
| /// \param other Another bound term to compare against | |
| /// \return true if the terms are equivalent, false otherwise | |
| virtual bool Equals(const BoundTerm& other) const = 0; | |
| friend bool operator==(const BoundTerm& lhs, const BoundTerm& rhs) { | |
| return lhs.Equals(rhs); | |
| } | |
| bool is_unbound() const override { return false; } | |
| }; | |
| /// \brief A reference represents a named field in an expression. | |
| class ICEBERG_EXPORT Reference { | |
| public: | |
| virtual ~Reference(); | |
| /// \brief Returns the name of the referenced field. | |
| virtual std::string_view name() const = 0; | |
| }; | |
| /// \brief A reference to an unbound named field. | |
| class ICEBERG_EXPORT NamedReference | |
| : public Reference, | |
| public UnboundTerm<BoundReference>, | |
| public std::enable_shared_from_this<NamedReference> { | |
| public: | |
| /// \brief Create a named reference to a field. | |
| /// | |
| /// \param field_name The name of the field to reference | |
| static Result<std::unique_ptr<NamedReference>> Make(std::string field_name); | |
| ~NamedReference() override; | |
| std::string_view name() const override { return field_name_; } | |
| Result<std::shared_ptr<BoundReference>> Bind(const Schema& schema, | |
| bool case_sensitive) const override; | |
| std::shared_ptr<const NamedReference> reference() const override { | |
| return shared_from_this(); | |
| } | |
| std::string ToString() const override; | |
| Kind kind() const override { return Kind::kReference; } | |
| private: | |
| explicit NamedReference(std::string field_name); | |
| std::string field_name_; | |
| }; | |
| /// \brief A reference to a bound field. | |
| class ICEBERG_EXPORT BoundReference | |
| : public Reference, | |
| public BoundTerm, | |
| public std::enable_shared_from_this<BoundReference> { | |
| public: | |
| /// \brief Create a bound reference. | |
| /// | |
| /// \param field The schema field | |
| static Result<std::unique_ptr<BoundReference>> Make( | |
| SchemaField field, std::unique_ptr<StructLikeAccessor> accessor); | |
| ~BoundReference() override; | |
| const SchemaField& field() const { return field_; } | |
| std::string_view name() const override { return field_.name(); } | |
| std::string ToString() const override; | |
| Result<Literal> Evaluate(const StructLike& data) const override; | |
| std::shared_ptr<BoundReference> reference() override { return shared_from_this(); } | |
| std::shared_ptr<Type> type() const override { return field_.type(); } | |
| int32_t field_id() const { return field_.field_id(); } | |
| bool MayProduceNull() const override { return field_.optional(); } | |
| bool Equals(const BoundTerm& other) const override; | |
| Kind kind() const override { return Kind::kReference; } | |
| const StructLikeAccessor& accessor() const { return *accessor_; } | |
| private: | |
| BoundReference(SchemaField field, std::unique_ptr<StructLikeAccessor> accessor); | |
| SchemaField field_; | |
| std::unique_ptr<StructLikeAccessor> accessor_; | |
| }; | |
| /// \brief An unbound transform expression. | |
| class ICEBERG_EXPORT UnboundTransform : public UnboundTerm<class BoundTransform> { | |
| public: | |
| /// \brief Create an unbound transform. | |
| /// | |
| /// \param ref The term to apply the transformation to | |
| /// \param transform The transformation function to apply | |
| static Result<std::unique_ptr<UnboundTransform>> Make( | |
| std::shared_ptr<NamedReference> ref, std::shared_ptr<Transform> transform); | |
| ~UnboundTransform() override; | |
| std::string ToString() const override; | |
| Result<std::shared_ptr<BoundTransform>> Bind(const Schema& schema, | |
| bool case_sensitive) const override; | |
| std::shared_ptr<const NamedReference> reference() const override { return ref_; } | |
| const std::shared_ptr<Transform>& transform() const { return transform_; } | |
| Kind kind() const override { return Kind::kTransform; } | |
| private: | |
| UnboundTransform(std::shared_ptr<NamedReference> ref, | |
| std::shared_ptr<Transform> transform); | |
| std::shared_ptr<NamedReference> ref_; | |
| std::shared_ptr<Transform> transform_; | |
| }; | |
| /// \brief A bound transform expression. | |
| class ICEBERG_EXPORT BoundTransform : public BoundTerm { | |
| public: | |
| /// \brief Create a bound transform. | |
| /// | |
| /// \param ref The bound term to apply the transformation to | |
| /// \param transform The transform to apply | |
| /// \param transform_func The bound transform function to apply | |
| static Result<std::unique_ptr<BoundTransform>> Make( | |
| std::shared_ptr<BoundReference> ref, std::shared_ptr<Transform> transform, | |
| std::shared_ptr<TransformFunction> transform_func); | |
| ~BoundTransform() override; | |
| std::string ToString() const override; | |
| Result<Literal> Evaluate(const StructLike& data) const override; | |
| std::shared_ptr<BoundReference> reference() override { return ref_; } | |
| std::shared_ptr<Type> type() const override; | |
| bool MayProduceNull() const override; | |
| bool Equals(const BoundTerm& other) const override; | |
| const std::shared_ptr<Transform>& transform() const { return transform_; } | |
| Kind kind() const override { return Kind::kTransform; } | |
| private: | |
| BoundTransform(std::shared_ptr<BoundReference> ref, | |
| std::shared_ptr<Transform> transform, | |
| std::shared_ptr<TransformFunction> transform_func); | |
| std::shared_ptr<BoundReference> ref_; | |
| std::shared_ptr<Transform> transform_; | |
| std::shared_ptr<TransformFunction> transform_func_; | |
| }; | |
| } // namespace iceberg |