flex/engines/graph_db/runtime/utils/expr_impl.h (807 lines of code) (raw):

/** Copyright 2020 Alibaba Group Holding Limited. * * Licensed 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. */ #ifndef RUNTIME_UTILS_RUNTIME_EXPR_IMPL_H_ #define RUNTIME_UTILS_RUNTIME_EXPR_IMPL_H_ #include "flex/proto_generated_gie/expr.pb.h" #include "flex/engines/graph_db/runtime/common/rt_any.h" #include "flex/engines/graph_db/runtime/utils/var.h" namespace gs { namespace runtime { class ExprBase { public: virtual RTAny eval_path(size_t idx, Arena&) const = 0; virtual RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const = 0; virtual RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const = 0; virtual RTAnyType type() const = 0; virtual RTAny eval_path(size_t idx, Arena& arena, int) const { return eval_path(idx, arena); } virtual RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena, int) const { return eval_vertex(label, v, idx, arena); } virtual RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena, int) const { return eval_edge(label, src, dst, data, idx, arena); } virtual bool is_optional() const { return false; } virtual RTAnyType elem_type() const { return RTAnyType::kEmpty; } virtual ~ExprBase() = default; }; class VertexWithInSetExpr : public ExprBase { public: VertexWithInSetExpr(const Context& ctx, std::unique_ptr<ExprBase>&& key, std::unique_ptr<ExprBase>&& val_set) : key_(std::move(key)), val_set_(std::move(val_set)) { assert(key_->type() == RTAnyType::kVertex); assert(val_set_->type() == RTAnyType::kSet); } RTAny eval_path(size_t idx, Arena& arena) const override { auto key = key_->eval_path(idx, arena).as_vertex(); auto set = val_set_->eval_path(idx, arena).as_set(); assert(set.impl_ != nullptr); auto ptr = dynamic_cast<SetImpl<VertexRecord>*>(set.impl_); assert(ptr != nullptr); return RTAny::from_bool(ptr->exists(key)); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { auto key = key_->eval_vertex(label, v, idx, arena).as_vertex(); auto set = val_set_->eval_vertex(label, v, idx, arena).as_set(); return RTAny::from_bool( dynamic_cast<SetImpl<VertexRecord>*>(set.impl_)->exists(key)); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { auto key = key_->eval_edge(label, src, dst, data, idx, arena).as_vertex(); auto set = val_set_->eval_edge(label, src, dst, data, idx, arena).as_set(); return RTAny::from_bool( dynamic_cast<SetImpl<VertexRecord>*>(set.impl_)->exists(key)); } RTAnyType type() const override { return RTAnyType::kBoolValue; } bool is_optional() const override { return key_->is_optional(); } private: std::unique_ptr<ExprBase> key_; std::unique_ptr<ExprBase> val_set_; }; class VertexWithInListExpr : public ExprBase { public: VertexWithInListExpr(const Context& ctx, std::unique_ptr<ExprBase>&& key, std::unique_ptr<ExprBase>&& val_list) : key_(std::move(key)), val_list_(std::move(val_list)) { assert(key_->type() == RTAnyType::kVertex); assert(val_list_->type() == RTAnyType::kList); } RTAny eval_path(size_t idx, Arena& arena) const override { auto key = key_->eval_path(idx, arena).as_vertex(); auto list = val_list_->eval_path(idx, arena).as_list(); for (size_t i = 0; i < list.size(); i++) { if (list.get(i).as_vertex() == key) { return RTAny::from_bool(true); } } return RTAny::from_bool(false); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { auto key = key_->eval_vertex(label, v, idx, arena).as_vertex(); auto list = val_list_->eval_vertex(label, v, idx, arena).as_list(); for (size_t i = 0; i < list.size(); i++) { if (list.get(i).as_vertex() == key) { return RTAny::from_bool(true); } } return RTAny::from_bool(false); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { auto key = key_->eval_edge(label, src, dst, data, idx, arena).as_vertex(); auto list = val_list_->eval_edge(label, src, dst, data, idx, arena).as_list(); for (size_t i = 0; i < list.size(); i++) { if (list.get(i).as_vertex() == key) { return RTAny::from_bool(true); } } return RTAny::from_bool(false); } RTAnyType type() const override { return RTAnyType::kBoolValue; } bool is_optional() const override { return key_->is_optional(); } std::unique_ptr<ExprBase> key_; std::unique_ptr<ExprBase> val_list_; }; #define PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(dst_vector_name, array_name) \ size_t len = array_name.item_size(); \ for (size_t idx = 0; idx < len; ++idx) { \ dst_vector_name.push_back(array_name.item(idx)); \ } template <typename T> class WithInExpr : public ExprBase { public: WithInExpr(const Context& ctx, std::unique_ptr<ExprBase>&& key, const common::Value& array) : key_(std::move(key)) { if constexpr (std::is_same_v<T, int64_t>) { if (array.item_case() == common::Value::kI64Array) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i64_array()); } else if (array.item_case() == common::Value::kI32Array) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i32_array()); } else { // TODO(zhanglei,lexiao): We should support more types here, and if type // conversion fails, we should return an error. LOG(INFO) << "Could not convert array with type " << array.item_case() << " to int64_t array"; } } else if constexpr (std::is_same_v<T, uint64_t>) { if (array.item_case() == common::Value::kI64Array) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i64_array()); } else if (array.item_case() == common::Value::kI32Array) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i32_array()); } else { LOG(INFO) << "Could not convert array with type " << array.item_case() << " to int64_t array"; } } else if constexpr (std::is_same_v<T, int32_t>) { if (array.item_case() == common::Value::kI32Array) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i32_array()); } else if constexpr (std::is_same_v<T, int64_t>) { PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.i64_array()); } else { LOG(INFO) << "Could not convert array with type " << array.item_case() << " to int32_t array"; } } else if constexpr (std::is_same_v<T, std::string>) { assert(array.item_case() == common::Value::kStrArray); PARSER_COMMON_VALUE_ARRAY_TO_VECTOR(container_, array.str_array()); } else { LOG(FATAL) << "not implemented"; } } RTAny eval_path(size_t idx, Arena& arena) const override { if constexpr (std::is_same_v<T, std::string>) { auto val = std::string(key_->eval_path(idx, arena).as_string()); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } else { auto val = TypedConverter<T>::to_typed(key_->eval_path(idx, arena)); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto any_val = key_->eval_path(idx, arena, 0); if (any_val.is_null()) { return RTAny::from_bool(false); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { if constexpr (std::is_same_v<T, std::string>) { auto val = std::string(key_->eval_vertex(label, v, idx, arena).as_string()); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } else { auto val = TypedConverter<T>::to_typed(key_->eval_vertex(label, v, idx, arena)); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena, int) const override { auto any_val = key_->eval_vertex(label, v, idx, arena, 0); if (any_val.is_null()) { return RTAny::from_bool(false); } return eval_vertex(label, v, idx, arena); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { if constexpr (std::is_same_v<T, std::string>) { auto val = std::string( key_->eval_edge(label, src, dst, data, idx, arena).as_string()); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } else { auto val = TypedConverter<T>::to_typed( key_->eval_edge(label, src, dst, data, idx, arena)); return RTAny::from_bool(std::find(container_.begin(), container_.end(), val) != container_.end()); } return RTAny::from_bool(false); } RTAnyType type() const override { return RTAnyType::kBoolValue; } bool is_optional() const override { return key_->is_optional(); } std::unique_ptr<ExprBase> key_; std::vector<T> container_; }; class VariableExpr : public ExprBase { public: template <typename GraphInterface> VariableExpr(const GraphInterface& graph, const Context& ctx, const common::Variable& pb, VarType var_type) : var_(graph, ctx, pb, var_type) {} RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; RTAny eval_path(size_t idx, Arena&, int) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&, int) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&, int) const override; bool is_optional() const override { return var_.is_optional(); } private: Var var_; }; class UnaryLogicalExpr : public ExprBase { public: UnaryLogicalExpr(std::unique_ptr<ExprBase>&& expr, common::Logical logic); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAny eval_path(size_t idx, Arena&, int) const override; RTAnyType type() const override; bool is_optional() const override { return expr_->is_optional(); } private: std::unique_ptr<ExprBase> expr_; common::Logical logic_; }; class LogicalExpr : public ExprBase { public: LogicalExpr(std::unique_ptr<ExprBase>&& lhs, std::unique_ptr<ExprBase>&& rhs, common::Logical logic); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAny eval_path(size_t idx, Arena& arena, int) const override { if (logic_ == common::Logical::OR) { bool flag = false; if (!lhs_->eval_path(idx, arena, 0).is_null()) { flag |= lhs_->eval_path(idx, arena, 0).as_bool(); } if (!rhs_->eval_path(idx, arena, 0).is_null()) { flag |= rhs_->eval_path(idx, arena, 0).as_bool(); } return RTAny::from_bool(flag); } if (lhs_->eval_path(idx, arena, 0).is_null() || rhs_->eval_path(idx, arena, 0).is_null()) { return RTAny::from_bool(false); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena, int) const override { if (logic_ == common::Logical::OR) { bool flag = false; if (!lhs_->eval_vertex(label, v, idx, arena, 0).is_null()) { flag |= lhs_->eval_vertex(label, v, idx, arena, 0).as_bool(); } if (!rhs_->eval_vertex(label, v, idx, arena, 0).is_null()) { flag |= rhs_->eval_vertex(label, v, idx, arena, 0).as_bool(); } return RTAny::from_bool(flag); } if (lhs_->eval_vertex(label, v, idx, arena, 0).is_null() || rhs_->eval_vertex(label, v, idx, arena, 0).is_null()) { return RTAny::from_bool(false); } return eval_vertex(label, v, idx, arena); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&, int) const override { LOG(FATAL) << "not implemented"; return RTAny(); } RTAnyType type() const override; bool is_optional() const override { return lhs_->is_optional() || rhs_->is_optional(); } private: std::unique_ptr<ExprBase> lhs_; std::unique_ptr<ExprBase> rhs_; std::function<bool(RTAny, RTAny)> op_; common::Logical logic_; }; int32_t extract_time_from_milli_second(int64_t ms, common::Extract extract); template <typename T> class ExtractExpr : public ExprBase { public: ExtractExpr(std::unique_ptr<ExprBase>&& expr, const common::Extract& extract) : expr_(std::move(expr)), extract_(extract) {} int32_t eval_impl(const RTAny& val) const { if constexpr (std::is_same_v<T, int64_t>) { return extract_time_from_milli_second(val.as_int64(), extract_); } else if constexpr (std::is_same_v<T, Date>) { return extract_time_from_milli_second(val.as_timestamp().milli_second, extract_); } else if constexpr (std::is_same_v<T, Day>) { if (extract_.interval() == common::Extract::DAY) { return val.as_date32().day(); } else if (extract_.interval() == common::Extract::MONTH) { return val.as_date32().month(); } else if (extract_.interval() == common::Extract::YEAR) { return val.as_date32().year(); } } LOG(FATAL) << "not support" << extract_.DebugString(); return 0; } RTAny eval_path(size_t idx, Arena& arena) const override { return RTAny::from_int32(eval_impl(expr_->eval_path(idx, arena))); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { return RTAny::from_int32( eval_impl(expr_->eval_vertex(label, v, idx, arena))); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { return RTAny::from_int32( eval_impl(expr_->eval_edge(label, src, dst, data, idx, arena))); } RTAnyType type() const override { return RTAnyType::kI32Value; } private: std::unique_ptr<ExprBase> expr_; const common::Extract extract_; }; class ArithExpr : public ExprBase { public: ArithExpr(std::unique_ptr<ExprBase>&& lhs, std::unique_ptr<ExprBase>&& rhs, common::Arithmetic arith); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; private: std::unique_ptr<ExprBase> lhs_; std::unique_ptr<ExprBase> rhs_; std::function<RTAny(RTAny, RTAny)> op_; common::Arithmetic arith_; }; class DateMinusExpr : public ExprBase { public: DateMinusExpr(std::unique_ptr<ExprBase>&& lhs, std::unique_ptr<ExprBase>&& rhs); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; private: std::unique_ptr<ExprBase> lhs_; std::unique_ptr<ExprBase> rhs_; }; class ConstExpr : public ExprBase { public: ConstExpr(const RTAny& val); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; bool is_optional() const override { return val_.is_null(); } private: RTAny val_; std::string s; }; class CaseWhenExpr : public ExprBase { public: CaseWhenExpr( std::vector<std::pair<std::unique_ptr<ExprBase>, std::unique_ptr<ExprBase>>>&& when_then_exprs, std::unique_ptr<ExprBase>&& else_expr); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; bool is_optional() const override { for (auto& expr_pair : when_then_exprs_) { if (expr_pair.first->is_optional() || expr_pair.second->is_optional()) { return true; } } return else_expr_->is_optional(); } private: std::vector<std::pair<std::unique_ptr<ExprBase>, std::unique_ptr<ExprBase>>> when_then_exprs_; std::unique_ptr<ExprBase> else_expr_; }; class TupleExpr : public ExprBase { public: TupleExpr(std::vector<std::unique_ptr<ExprBase>>&& exprs); RTAny eval_path(size_t idx, Arena&) const override; RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override; RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override; RTAnyType type() const override; private: std::vector<std::unique_ptr<ExprBase>> exprs_; }; template <typename... Args> class TypedTupleExpr : public ExprBase { public: TypedTupleExpr(std::array<std::unique_ptr<ExprBase>, sizeof...(Args)>&& exprs) : exprs_(std::move(exprs)) { assert(exprs.size() == sizeof...(Args)); } template <std::size_t... Is> std::tuple<Args...> eval_path_impl(std::index_sequence<Is...>, size_t idx, Arena& arena) const { return std::make_tuple( TypedConverter<Args>::to_typed(exprs_[Is]->eval_path(idx, arena))...); } RTAny eval_path(size_t idx, Arena& arena) const override { auto tup = eval_path_impl(std::index_sequence_for<Args...>(), idx, arena); auto t = Tuple::make_tuple_impl(std::move(tup)); Tuple ret(t.get()); arena.emplace_back(std::move(t)); return RTAny::from_tuple(ret); } template <std::size_t... Is> std::tuple<Args...> eval_vertex_impl(std::index_sequence<Is...>, label_t label, vid_t v, size_t idx, Arena& arena) const { return std::make_tuple(TypedConverter<Args>::to_typed( exprs_[Is]->eval_vertex(label, v, idx, arena))...); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { auto tup = eval_vertex_impl(std::index_sequence_for<Args...>(), label, v, idx, arena); auto t = Tuple::make_tuple_impl(std::move(tup)); Tuple ret(t.get()); arena.emplace_back(std::move(t)); return RTAny::from_tuple(ret); } template <std::size_t... Is> std::tuple<Args...> eval_edge_impl(std::index_sequence<Is...>, const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const { return std::make_tuple(TypedConverter<Args>::to_typed( exprs_[Is]->eval_edge(label, src, dst, data, idx, arena))...); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { auto tup = eval_edge_impl(std::index_sequence_for<Args...>(), label, src, dst, data, idx, arena); auto t = Tuple::make_tuple_impl(std::move(tup)); Tuple ret(t.get()); arena.emplace_back(std::move(t)); return RTAny::from_tuple(ret); } RTAnyType type() const override { return RTAnyType::kTuple; } private: std::array<std::unique_ptr<ExprBase>, sizeof...(Args)> exprs_; }; class MapExpr : public ExprBase { public: MapExpr(std::vector<RTAny>&& keys, std::vector<std::unique_ptr<ExprBase>>&& values) : keys(std::move(keys)), value_exprs(std::move(values)) { assert(keys.size() == values.size()); } RTAny eval_path(size_t idx, Arena& arena) const override { std::vector<RTAny> ret; for (size_t i = 0; i < keys.size(); i++) { ret.push_back(value_exprs[i]->eval_path(idx, arena)); } auto map_impl = MapImpl::make_map_impl(keys, ret); auto map = Map::make_map(map_impl.get()); arena.emplace_back(std::move(map_impl)); return RTAny::from_map(map); } RTAny eval_path(size_t idx, Arena& arena, int) const override { std::vector<RTAny> ret; for (size_t i = 0; i < keys.size(); i++) { ret.push_back(value_exprs[i]->eval_path(idx, arena, 0)); } auto map_impl = MapImpl::make_map_impl(keys, ret); auto map = Map::make_map(map_impl.get()); arena.emplace_back(std::move(map_impl)); return RTAny::from_map(map); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override { LOG(FATAL) << "not implemented"; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override { LOG(FATAL) << "not implemented"; return RTAny(); } RTAnyType type() const override { return RTAnyType::kMap; } bool is_optional() const override { for (auto& expr : value_exprs) { if (expr->is_optional()) { return true; } } return false; } private: std::vector<RTAny> keys; std::vector<std::unique_ptr<ExprBase>> value_exprs; }; class ListExprBase : public ExprBase { public: ListExprBase() = default; RTAnyType type() const override { return RTAnyType::kList; } }; class RelationshipsExpr : public ListExprBase { public: RelationshipsExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { assert(args->type() == RTAnyType::kPath); auto path = args->eval_path(idx, arena).as_path(); auto rels = path.relationships(); auto ptr = ListImpl<Relation>::make_list_impl(std::move(rels)); List rel_list(ptr.get()); arena.emplace_back(std::move(ptr)); return RTAny::from_list(rel_list); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto path = args->eval_path(idx, arena, 0); if (path.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } bool is_optional() const override { return args->is_optional(); } RTAnyType elem_type() const override { return RTAnyType::kRelation; } private: std::unique_ptr<ExprBase> args; }; class NodesExpr : public ListExprBase { public: NodesExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { assert(args->type() == RTAnyType::kPath); auto path = args->eval_path(idx, arena).as_path(); auto nodes = path.nodes(); auto ptr = ListImpl<VertexRecord>::make_list_impl(std::move(nodes)); List node_list(ptr.get()); arena.emplace_back(std::move(ptr)); return RTAny::from_list(node_list); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto path = args->eval_path(idx, arena, 0); if (path.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } bool is_optional() const override { return args->is_optional(); } RTAnyType elem_type() const override { return RTAnyType::kVertex; } private: std::unique_ptr<ExprBase> args; }; class StartNodeExpr : public ExprBase { public: StartNodeExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { assert(args->type() == RTAnyType::kRelation); auto path = args->eval_path(idx, arena).as_relation(); auto node = path.start_node(); return RTAny::from_vertex(node); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto path = args->eval_path(idx, arena, 0); if (path.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAnyType type() const override { return RTAnyType::kVertex; } bool is_optional() const override { return args->is_optional(); } private: std::unique_ptr<ExprBase> args; }; class EndNodeExpr : public ExprBase { public: EndNodeExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { assert(args->type() == RTAnyType::kRelation); auto path = args->eval_path(idx, arena).as_relation(); auto node = path.end_node(); return RTAny::from_vertex(node); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto path = args->eval_path(idx, arena, 0); if (path.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena&) const override { LOG(FATAL) << "should not be called"; return RTAny(); } RTAnyType type() const override { return RTAnyType::kVertex; } bool is_optional() const override { return args->is_optional(); } private: std::unique_ptr<ExprBase> args; }; class ToFloatExpr : public ExprBase { public: static double to_double(const RTAny& val) { if (val.type() == RTAnyType::kI64Value) { return static_cast<double>(val.as_int64()); } else if (val.type() == RTAnyType::kI32Value) { return static_cast<double>(val.as_int32()); } else if (val.type() == RTAnyType::kF64Value) { return val.as_double(); } else { LOG(FATAL) << "invalid type"; } } ToFloatExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { auto val = args->eval_path(idx, arena); return RTAny::from_double(to_double(val)); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto val = args->eval_path(idx, arena, 0); if (val.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { auto val = args->eval_vertex(label, v, idx, arena); return RTAny::from_double(to_double(val)); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { auto val = args->eval_edge(label, src, dst, data, idx, arena); return RTAny::from_double(to_double(val)); } RTAnyType type() const override { return RTAnyType::kF64Value; } bool is_optional() const override { return args->is_optional(); } private: std::unique_ptr<ExprBase> args; }; class StrConcatExpr : public ExprBase { public: StrConcatExpr(std::unique_ptr<ExprBase>&& lhs, std::unique_ptr<ExprBase>&& rhs) : lhs(std::move(lhs)), rhs(std::move(rhs)) {} RTAny eval_path(size_t idx, Arena& arena) const override { std::string ret = std::string(lhs->eval_path(idx, arena).as_string()) + ";" + std::string(rhs->eval_path(idx, arena).as_string()); auto ptr = StringImpl::make_string_impl(ret); auto sv = ptr->str_view(); arena.emplace_back(std::move(ptr)); return RTAny::from_string(sv); } RTAny eval_path(size_t idx, Arena& arena, int) const override { if (lhs->eval_path(idx, arena, 0).is_null() || rhs->eval_path(idx, arena, 0).is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { std::string ret = std::string(lhs->eval_vertex(label, v, idx, arena).as_string()) + ";" + std::string(rhs->eval_vertex(label, v, idx, arena).as_string()); auto ptr = StringImpl::make_string_impl(ret); auto sv = ptr->str_view(); arena.emplace_back(std::move(ptr)); return RTAny::from_string(sv); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { std::string ret = std::string( lhs->eval_edge(label, src, dst, data, idx, arena).as_string()) + ";" + std::string( rhs->eval_edge(label, src, dst, data, idx, arena).as_string()); auto ptr = StringImpl::make_string_impl(ret); auto sv = ptr->str_view(); arena.emplace_back(std::move(ptr)); return RTAny::from_string(sv); } RTAnyType type() const override { return RTAnyType::kStringValue; } bool is_optional() const override { return lhs->is_optional() || rhs->is_optional(); } private: std::unique_ptr<ExprBase> lhs; std::unique_ptr<ExprBase> rhs; }; class StrListSizeExpr : public ExprBase { public: StrListSizeExpr(std::unique_ptr<ExprBase>&& args) : args(std::move(args)) {} RTAny eval_path(size_t idx, Arena& arena) const override { CHECK(args->type() == RTAnyType::kStringValue); auto str_list = args->eval_path(idx, arena).as_string(); return RTAny::from_int32(_size(str_list)); } RTAny eval_path(size_t idx, Arena& arena, int) const override { auto list = args->eval_path(idx, arena, 0); if (list.is_null()) { return RTAny(RTAnyType::kNull); } return eval_path(idx, arena); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, Arena& arena) const override { auto str_list = args->eval_vertex(label, v, idx, arena).as_string(); return RTAny::from_int32(_size(str_list)); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, Arena& arena) const override { auto str_list = args->eval_edge(label, src, dst, data, idx, arena).as_string(); return RTAny::from_int32(_size(str_list)); } RTAnyType type() const override { return RTAnyType::kI32Value; } bool is_optional() const override { return args->is_optional(); } private: int32_t _size(const std::string_view& sv) const { if (sv.empty()) { return 0; } int64_t ret = 1; for (auto c : sv) { if (c == ';') { ++ret; } } return ret; } std::unique_ptr<ExprBase> args; }; template <typename GraphInterface> std::unique_ptr<ExprBase> parse_expression( const GraphInterface& graph, const Context& ctx, const std::map<std::string, std::string>& params, const common::Expression& expr, VarType var_type); } // namespace runtime } // namespace gs #endif // RUNTIME_UTILS_RUNTIME_EXPR_IMPL_H_