
/** 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 ENGINES_HQPS_ENGINE_KEYED_UTILS_H_
#define ENGINES_HQPS_ENGINE_KEYED_UTILS_H_

#include "flex/engines/hqps_db/core/utils/props.h"
#include "flex/engines/hqps_db/database/mutable_csr_interface.h"
#include "flex/engines/hqps_db/structures/collection.h"
#include "flex/engines/hqps_db/structures/multi_edge_set/adj_edge_set.h"
#include "flex/engines/hqps_db/structures/multi_edge_set/untyped_edge_set.h"
#include "flex/engines/hqps_db/structures/multi_vertex_set/general_vertex_set.h"
#include "flex/engines/hqps_db/structures/multi_vertex_set/keyed_row_vertex_set.h"
#include "flex/engines/hqps_db/structures/multi_vertex_set/row_vertex_set.h"
#include "flex/engines/hqps_db/structures/multi_vertex_set/two_label_vertex_set.h"
#include "flex/engines/hqps_db/structures/path.h"

namespace gs {

template <typename SET_T>
struct AggFirst;

template <typename T>
struct AggFirst<Collection<T>> {
  using result_t = Collection<T>;
};

template <typename LabelT, typename VID_T, typename... T>
struct AggFirst<RowVertexSetImpl<LabelT, VID_T, T...>> {
  using result_t = RowVertexSetImpl<LabelT, VID_T, T...>;
};

template <typename VID_T, typename LabelT, typename... T>
struct AggFirst<TwoLabelVertexSetImpl<VID_T, LabelT, T...>> {
  using result_t = TwoLabelVertexSetImpl<VID_T, LabelT, T...>;
};

template <typename VID_T, typename LabelT, typename... T>
struct AggFirst<GeneralVertexSet<VID_T, LabelT, T...>> {
  using result_t = GeneralVertexSet<VID_T, LabelT, T...>;
};

/// @brief Helper to get keyed set type
/// @tparam T
/// @tparam ValueT Keyed prop type
template <typename T, typename KEY_ALIAS_T>
struct KeyedT;

// group by the vertex set itself
template <typename LabelT, typename VID_T, typename... T>
struct KeyedT<RowVertexSet<LabelT, VID_T, T...>,
              PropertySelector<grape::EmptyType>> {
  using keyed_set_t = KeyedRowVertexSet<LabelT, VID_T, VID_T, T...>;
  // // The builder type.
  using keyed_builder_t = KeyedRowVertexSetBuilder<LabelT, VID_T, VID_T, T...>;
  using unkeyed_builder_t = RowVertexSetBuilder<LabelT, VID_T, T...>;

  static keyed_builder_t create_keyed_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return keyed_builder_t(set);
  }

  static unkeyed_builder_t create_unkeyed_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return set.CreateBuilder();
  }
};

// Group By TwoLabelVertexSet's internal id.
template <typename LabelT, typename VID_T, typename... T>
struct KeyedT<TwoLabelVertexSet<VID_T, LabelT, T...>,
              PropertySelector<grape::EmptyType>> {
  using keyed_set_t = TwoLabelVertexSet<VID_T, LabelT, T...>;
  // // The builder type.
  using keyed_builder_t =
      TwoLabelVertexSetImplKeyedBuilder<VID_T, LabelT, T...>;
  using unkeyed_builder_t = TwoLabelVertexSetImplBuilder<VID_T, LabelT, T...>;

  static keyed_builder_t create_keyed_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return keyed_builder_t(set);
  }

  static unkeyed_builder_t create_unkeyed_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return set.CreateBuilder();
  }
};

// Group By TwoLabelVertexSet's other properties
template <typename LabelT, typename VID_T, typename... T, typename PropT>
struct KeyedT<TwoLabelVertexSet<VID_T, LabelT, T...>, PropertySelector<PropT>> {
  using keyed_set_t = Collection<PropT>;
  // // The builder type.
  using keyed_builder_t = KeyedCollectionBuilder<PropT>;
  using unkeyed_builder_t = CollectionBuilder<PropT>;

  static keyed_builder_t create_keyed_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<PropT>& selector) {
    return keyed_builder_t();
  }

  static unkeyed_builder_t create_unkeyed_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return unkeyed_builder_t();
  }
};

// group by the vertex set' property
template <typename LabelT, typename VID_T, typename... T, typename PropT>
struct KeyedT<RowVertexSet<LabelT, VID_T, T...>, PropertySelector<PropT>> {
  using keyed_set_t = Collection<PropT>;
  // // The builder type.
  using keyed_builder_t = KeyedCollectionBuilder<PropT>;
  using unkeyed_builder_t = CollectionBuilder<PropT>;

  static keyed_builder_t create_keyed_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set,
      const PropertySelector<PropT>& selector) {
    return keyed_builder_t(set);
  }

  static unkeyed_builder_t create_unkeyed_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set,
      const PropertySelector<PropT>& selector) {
    return unkeyed_builder_t();
  }
};

// key on a keyed row vertex get us a unkeyed set.
template <typename LabelT, typename KEY_T, typename VID_T, typename... SET_T>
struct KeyedT<KeyedRowVertexSetImpl<LabelT, KEY_T, VID_T, SET_T...>,
              PropertySelector<grape::EmptyType>> {
  using keyed_set_t = KeyedRowVertexSetImpl<LabelT, VID_T, SET_T...>;
  // // The builder type.
  using keyed_builder_t =
      KeyedRowVertexSetBuilder<LabelT, KEY_T, VID_T, SET_T...>;
  using unkeyed_builder_t =
      typename KeyedRowVertexSetImpl<LabelT, KEY_T, VID_T, SET_T...>::builder_t;
  static keyed_builder_t create_keyed_builder(
      const KeyedRowVertexSetImpl<LabelT, KEY_T, VID_T, SET_T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return builder_t(set);
  }
  static unkeyed_builder_t create_unkeyedkeyed_builder(
      const KeyedRowVertexSetImpl<LabelT, KEY_T, VID_T, SET_T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return set.CreateBuilder();
  }
};

// group by vertex set' id, for generate vertex set.
template <typename VID_T, typename LabelT, typename... T>
struct KeyedT<GeneralVertexSet<VID_T, LabelT, T...>,
              PropertySelector<grape::EmptyType>> {
  using keyed_builder_t = GeneralVertexSetKeyedBuilder<VID_T, LabelT, T...>;
  using keyed_set_t = GeneralVertexSet<VID_T, LabelT, T...>;
  using unkeyed_builder_t =
      typename GeneralVertexSet<LabelT, VID_T, LabelT, T...>::builder_t;
  static keyed_builder_t create_keyed_builder(
      const GeneralVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return keyed_builder_t(set);
  }
  static unkeyed_builder_t create_unkeyedkeyed_builder(
      const GeneralVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return set.CreateBuilder();
  }
};

template <typename VID_T, typename LabelT, typename... T>
struct KeyedT<GeneralVertexSet<VID_T, LabelT, T...>,
              PropertySelector<LabelKey>> {
  using keyed_set_t = Collection<LabelKey>;
  using keyed_builder_t = KeyedCollectionBuilder<LabelKey>;

  static keyed_builder_t create_keyed_builder(
      const GeneralVertexSet<VID_T, LabelT, T...>& set,
      const PropertySelector<LabelKey>& selector) {
    return keyed_builder_t();
  }
};

template <typename T>
struct KeyedT<Collection<T>, PropertySelector<grape::EmptyType>> {
  using keyed_set_t = Collection<T>;
  // // The builder type.
  using keyed_builder_t = KeyedCollectionBuilder<T>;
  using unkeyed_builder_t = CollectionBuilder<T>;

  static keyed_builder_t create_keyed_builder(
      const Collection<T>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return keyed_builder_t(set);
  }
  static unkeyed_builder_t create_unkeyed_builder(
      const Collection<T>& set,
      const PropertySelector<grape::EmptyType>& selector) {
    return unkeyed_builder_t();
  }
};

// when keyed with aggregation function, (which we currently only support
// collection)

/// @brief Helper to get keyed set type with aggregation func
/// @tparam T
/// @tparam ValueT Keyed prop type
template <typename GI, typename T, AggFunc agg_func, typename Props,
          typename Tags>
struct KeyedAggT;

/// @brief Helper to get keyed set type with aggregation func, which is applied
/// on multiple column
/// @tparam T
/// @tparam ValueT Keyed prop type
template <typename GI, typename SET_TUPLE_T, AggFunc agg_func, typename Props,
          typename Tags>
struct KeyedAggMultiColT;

template <typename GI, typename LabelT, typename VID_T, typename... T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::COUNT,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using index_ele_t =
      typename RowVertexSet<LabelT, VID_T, T...>::index_ele_tuple_t;
  using prop_getter_t = RowVertexSetPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  // build a counter array.
  using aggregate_res_builder_t = PropCountBuilder<tag_id, prop_getter_t>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selector) {
    auto prop_getter = create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selector).prop_name_);
    return aggregate_res_builder_t(std::move(prop_getter));
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  // build a counter array.
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selector) {
    return CountBuilder<tag_id>();
  }
};

// aggregate count_dist
template <typename GI, typename LabelT, typename VID_T, typename... T,
          int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::COUNT_DISTINCT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  // build a counter array.
  using vertex_set_t = RowVertexSet<LabelT, VID_T, T...>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, vertex_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set.GetVertices());
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          int tag_id>
struct KeyedAggT<GI, GeneralVertexSet<VID_T, LabelT, T...>,
                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  // build a counter array.
  using vertex_set_t = GeneralVertexSet<VID_T, LabelT, T...>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, vertex_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const vertex_set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set.GetBitsets(), set.GetLabels());
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>, AggFunc::COUNT,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  using index_ele_t =
      typename TwoLabelVertexSet<VID_T, LabelT, T...>::index_ele_tuple_t;
  // build a counter array.
  using prop_getter_t = TwoLabelVertexSetImplPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = PropCountBuilder<tag_id, prop_getter_t>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    auto prop_getter = create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_);
    return aggregate_res_builder_t(std::move(prop_getter));
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... T,
          int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  // build a counter array.
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

// count distinct for two_label set.
template <typename GI, typename VID_T, typename LabelT, typename... T,
          int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>,
                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  // build a counter array.
  using vertex_set_t = TwoLabelVertexSet<VID_T, LabelT, T...>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, vertex_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set.GetBitset(), set.GetVertices());
  }
};

// general vertex set to_count
template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, GeneralVertexSet<VID_T, LabelT, SET_T...>, AggFunc::COUNT,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  using index_ele_t =
      typename GeneralVertexSet<VID_T, LabelT, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = GeneralVertexSetPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;

  // build a counter array.
  using aggregate_res_builder_t = PropCountBuilder<tag_id, prop_getter_t>;

  static aggregate_res_builder_t create_agg_builder(
      const GeneralVertexSet<VID_T, LabelT, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    auto prop_getter = create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_);
    return aggregate_res_builder_t(std::move(prop_getter));
  }
};

// count internal for general vertex set.
template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          int tag_id>
struct KeyedAggT<GI, GeneralVertexSet<VID_T, LabelT, SET_T...>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<int64_t>;
  // build a counter array.
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const GeneralVertexSet<VID_T, LabelT, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename T, int tag_id>
struct KeyedAggT<GI, Collection<T>, AggFunc::SUM, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<T>;
  using prop_getter_t = CollectionPropGetter<tag_id, T>;
  // build a counter array.
  using aggregate_res_builder_t = SumBuilder<prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(prop_getter_t());
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, SET_T...>, AggFunc::SUM,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using index_ele_t =
      typename TwoLabelVertexSet<VID_T, LabelT, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = TwoLabelVertexSetImplPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = SumBuilder<prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_));
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::TO_SET,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = CollectionOfVec<PropT>;
  using aggregate_res_builder_t =
      CollectionOfSetBuilder<PropT, GI, RowVertexSet<LabelT, VID_T, T...>,
                             tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return CollectionOfSetBuilder<PropT, GI, RowVertexSet<LabelT, VID_T, T...>,
                                  tag_id>(
        set, graph, std::array{std::get<0>(selectors).prop_name_});
  }
};

// to_vector
template <typename GI, typename T, typename PropT, int tag_id>
struct KeyedAggT<GI, Collection<T>, AggFunc::TO_LIST, std::tuple<PropT>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = CollectionOfVec<PropT>;
  using aggregate_res_builder_t =
      CollectionOfVecBuilder<T, GI, Collection<T>, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<T>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(
        graph, set, std::array{std::get<0>(selectors).prop_name_});
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::TO_LIST,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  static_assert(!std::is_same_v<PropT, grape::EmptyType>,
                "Aggregate to_list for vertex set it self is not allowed");
  using agg_res_t = CollectionOfVec<PropT>;
  using aggregate_res_builder_t =
      CollectionOfVecBuilder<PropT, GI, RowVertexSet<LabelT, VID_T, T...>,
                             tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(set, graph,
                                   {std::get<0>(selectors).prop_name_});
  }
};

// Aggregate to_list for twolabel vertex set's internal id.
template <typename GI, typename LabelT, typename VID_T, typename... T,
          int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::TO_LIST,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = CollectionOfVec<GlobalId>;
  using aggregate_res_builder_t =
      CollectionOfVecBuilder<grape::EmptyType, GI,
                             RowVertexSet<LabelT, VID_T, T...>, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set.GetLabel());
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>, AggFunc::TO_LIST,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = CollectionOfVec<PropT>;
  using aggregate_res_builder_t =
      CollectionOfVecBuilder<PropT, GI, TwoLabelVertexSet<VID_T, LabelT, T...>,
                             tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(set, graph,
                                   {std::get<0>(selectors).prop_name_});
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... T,
          int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>, AggFunc::TO_LIST,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = CollectionOfVec<GlobalId>;
  using aggregate_res_builder_t =
      CollectionOfVecBuilder<grape::EmptyType, GI,
                             TwoLabelVertexSet<VID_T, LabelT, T...>, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set.GetLabels());
  }
};

// get min
template <typename GI, typename PropT, int tag_id>
struct KeyedAggT<GI, Collection<PropT>, AggFunc::MIN,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using PropGetterT = CollectionPropGetter<tag_id, PropT>;
  using aggregate_res_builder_t = MinBuilder<GI, PropGetterT, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<PropT>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(PropGetterT());
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, SET_T...>, AggFunc::MIN,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using index_ele_t =
      typename RowVertexSet<LabelT, VID_T, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = RowVertexSetPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = MinBuilder<GI, prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_));
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, SET_T...>, AggFunc::MIN,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using index_ele_t =
      typename TwoLabelVertexSet<VID_T, LabelT, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = TwoLabelVertexSetImplPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = MinBuilder<GI, prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_));
  }
};

// get max
template <typename GI, typename PropT, int tag_id>
struct KeyedAggT<GI, Collection<PropT>, AggFunc::MAX, std::tuple<PropT>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using prop_getter_t = CollectionPropGetter<tag_id, PropT>;
  using aggregate_res_builder_t = MaxBuilder<GI, prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<PropT>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(prop_getter_t());
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, SET_T...>, AggFunc::MAX,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using index_ele_t =
      typename RowVertexSet<LabelT, VID_T, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = RowVertexSetPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = MaxBuilder<GI, prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const RowVertexSet<LabelT, VID_T, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_));
  }
};

template <typename GI, typename LabelT, typename VID_T, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, SET_T...>, AggFunc::MAX,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using index_ele_t =
      typename TwoLabelVertexSet<VID_T, LabelT, SET_T...>::index_ele_tuple_t;
  using prop_getter_t = TwoLabelVertexSetImplPropGetter<
      tag_id, gs::mutable_csr_graph_impl::SinglePropGetter<PropT>, index_ele_t>;
  using aggregate_res_builder_t = MaxBuilder<GI, prop_getter_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const TwoLabelVertexSet<VID_T, LabelT, SET_T...>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(create_prop_getter_impl<tag_id, PropT>(
        set, graph, std::get<0>(selectors).prop_name_));
  }
};

template <typename GI, typename T, typename PropT, int tag_id>
struct KeyedAggT<GI, Collection<T>, AggFunc::FIRST, std::tuple<PropT>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<T>;
  using aggregate_res_builder_t =
      FirstBuilder<GI, Collection<T>, PropT, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<T>& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(set, graph,
                                   {std::get<0>(selectors).prop_name_});
  }
};

// Aggregate first for twolabel vertex set
template <typename GI, typename VID_T, typename LabelT, typename... T,
          int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSetImpl<VID_T, LabelT, T...>, AggFunc::FIRST,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = TwoLabelVertexSetImpl<VID_T, LabelT, T...>;
  using old_set_t = TwoLabelVertexSetImpl<VID_T, LabelT, T...>;
  using aggregate_res_builder_t =
      FirstBuilder<GI, TwoLabelVertexSetImpl<VID_T, LabelT, T...>,
                   grape::EmptyType, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const old_set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(
        set, graph, std::array{std::get<0>(selectors).prop_name_});
  }
};

// Aggregate first for general vertex set
template <typename GI, typename VID_T, typename LabelT, typename... T,
          int tag_id>
struct KeyedAggT<GI, GeneralVertexSet<VID_T, LabelT, T...>, AggFunc::FIRST,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = GeneralVertexSet<VID_T, LabelT, T...>;
  using old_set_t = GeneralVertexSet<VID_T, LabelT, T...>;
  using aggregate_res_builder_t =
      FirstBuilder<GI, GeneralVertexSet<VID_T, LabelT, T...>, grape::EmptyType,
                   tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const old_set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(
        set, graph, std::array{std::get<0>(selectors).prop_name_});
  }
};

template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>,
                 AggFunc::COUNT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>& set,
      const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename VID_T, typename LabelT, typename SET_T,
          int tag_id>
struct KeyedAggT<GI, SingleLabelEdgeSet<VID_T, LabelT, SET_T>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const SingleLabelEdgeSet<VID_T, LabelT, SET_T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename VID_T, typename LabelT, typename EDATA_T,
          int tag_id>
struct KeyedAggT<GI, FlatEdgeSet<VID_T, LabelT, EDATA_T>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const FlatEdgeSet<VID_T, LabelT, EDATA_T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, CompressedPathSet<VID_T, LabelT>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const CompressedPathSet<VID_T, LabelT>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, PathSet<VID_T, LabelT>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const PathSet<VID_T, LabelT>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

template <typename GI, typename T, int tag_id>
struct KeyedAggT<GI, Collection<T>, AggFunc::COUNT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using aggregate_res_builder_t = CountBuilder<tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const Collection<T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return CountBuilder<tag_id>();
  }
};

// COUNT DISTINCT for EdgeSets.
template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>,
                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using edge_set_t = UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>& set,
      const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

template <typename GI, typename VID_T, typename LabelT, typename SET_T,
          int tag_id>
struct KeyedAggT<GI, SingleLabelEdgeSet<VID_T, LabelT, SET_T>,
                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using edge_set_t = SingleLabelEdgeSet<VID_T, LabelT, SET_T>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const SingleLabelEdgeSet<VID_T, LabelT, SET_T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

template <typename GI, typename VID_T, typename LabelT, typename EDATA_T,
          int tag_id>
struct KeyedAggT<GI, FlatEdgeSet<VID_T, LabelT, EDATA_T>,
                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using edge_set_t = FlatEdgeSet<VID_T, LabelT, EDATA_T>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const FlatEdgeSet<VID_T, LabelT, EDATA_T>& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, CompressedPathSet<VID_T, LabelT>, AggFunc::COUNT_DISTINCT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using path_set_t = CompressedPathSet<VID_T, LabelT>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, path_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const path_set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

template <typename GI, typename VID_T, typename LabelT, int tag_id>
struct KeyedAggT<GI, PathSet<VID_T, LabelT>, AggFunc::COUNT_DISTINCT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using path_set_t = PathSet<VID_T, LabelT>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, path_set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const path_set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

template <typename GI, typename T, int tag_id>
struct KeyedAggT<GI, Collection<T>, AggFunc::COUNT_DISTINCT,
                 std::tuple<grape::EmptyType>,
                 std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<size_t>;
  using set_t = Collection<T>;
  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, set_t>;

  static aggregate_res_builder_t create_agg_builder(
      const set_t& set, const GI& graph,
      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
    return aggregate_res_builder_t(set);
  }
};

// aggregate average.

template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, RowVertexSetImpl<LabelT, VID_T, SET_T...>, AggFunc::AVG,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using set_t = RowVertexSetImpl<LabelT, VID_T, SET_T...>;
  using aggregate_res_builder_t = AvgBuilder<PropT, GI, set_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const set_t& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(set, graph,
                                   {std::get<0>(selectors).prop_name_});
  }
};

template <typename GI, typename VID_T, typename LabelT, typename... SET_T,
          typename PropT, int tag_id>
struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, SET_T...>, AggFunc::AVG,
                 std::tuple<PropT>, std::integer_sequence<int32_t, tag_id>> {
  using agg_res_t = Collection<PropT>;
  using set_t = TwoLabelVertexSet<VID_T, LabelT, SET_T...>;
  using aggregate_res_builder_t = AvgBuilder<PropT, GI, set_t, tag_id>;

  static aggregate_res_builder_t create_agg_builder(
      const set_t& set, const GI& graph,
      std::tuple<PropertySelector<PropT>>& selectors) {
    return aggregate_res_builder_t(set, graph,
                                   {std::get<0>(selectors).prop_name_});
  }
};

template <typename GI, typename... SET_T, typename... PropSelectorT,
          int... tag_ids>
struct KeyedAggMultiColT<GI, std::tuple<SET_T...>, AggFunc::COUNT_DISTINCT,
                         std::tuple<PropSelectorT...>,
                         std::integer_sequence<int32_t, tag_ids...>> {
  using agg_res_t = Collection<size_t>;
  // get the tuple of sets from the tuple of tags.
  using aggregate_res_builder_t =
      MultiColDistinctCountBuilder<std::tuple<SET_T...>, tag_ids...>;

  static aggregate_res_builder_t create_agg_builder(
      const std::tuple<SET_T...>& set, const GI& graph,
      std::tuple<PropSelectorT...>& selectors) {
    return aggregate_res_builder_t();
  }
};

template <typename GI, typename... SET_T, typename... PropSelectorT,
          int... tag_ids>
struct KeyedAggMultiColT<GI, std::tuple<SET_T...>, AggFunc::COUNT,
                         std::tuple<PropSelectorT...>,
                         std::integer_sequence<int32_t, tag_ids...>> {
  using agg_res_t = Collection<size_t>;
  // get the tuple of sets from the tuple of tags.
  using aggregate_res_builder_t = MultiColCountBuilder<tag_ids...>;

  static aggregate_res_builder_t create_agg_builder(
      const std::tuple<SET_T...>& set, const GI& graph,
      std::tuple<PropSelectorT...>& selectors) {
    return aggregate_res_builder_t();
  }
};

template <typename LabelT, typename KEY_T, typename VID_T, typename... T,
          typename ELE, typename DATA>
static inline auto insert_into_builder_v2_impl(
    KeyedRowVertexSetBuilderImpl<LabelT, KEY_T, VID_T, T...>& builder,
    const ELE& ele, const DATA& data) {
  return builder.insert(ele, data);
}

template <typename LabelT, typename KEY_T, typename VID_T, typename ELE,
          typename DATA>
static inline auto insert_into_builder_v2_impl(
    KeyedRowVertexSetBuilderImpl<LabelT, KEY_T, VID_T, grape::EmptyType>&
        builder,
    const ELE& ele, const DATA& data) {
  return builder.Insert(ele);
}

// insert_into_bulder_v2_impl
template <
    typename BuilderT, typename ELE, typename DATA,
    typename std::enable_if<
        (BuilderT::is_row_vertex_set_builder &&
         std::is_same_v<DATA, std::tuple<grape::EmptyType>>)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele);
}

// insert_into_bulder_v2_impl
template <
    typename BuilderT, typename ELE, typename DATA,
    typename std::enable_if<
        (BuilderT::is_row_vertex_set_builder &&
         !std::is_same_v<DATA, std::tuple<grape::EmptyType>>)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele, data);
}

// insert into general vertex set builder
template <typename BuilderT, typename ELE, typename DATA,
          typename std::enable_if<
              (BuilderT::is_general_vertex_set_builder)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele, data);
}

template <typename VID_T, typename LabelT, typename EDATA_T, typename ELE,
          typename DATA>
static inline auto insert_into_builder_v2_impl(
    FlatEdgeSetBuilder<VID_T, LabelT, EDATA_T>& builder, const ELE& ele,
    const DATA& data) {
  return builder.Insert(ele);
}

template <typename BuilderT, typename ELE, typename DATA,
          typename std::enable_if<
              (BuilderT::is_general_edge_set_builder)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele);
}

template <
    typename BuilderT, typename ELE, typename DATA,
    typename std::enable_if<
        (BuilderT::is_two_label_set_builder &&
         std::is_same_v<DATA, std::tuple<grape::EmptyType>>)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele);
}

template <
    typename BuilderT, typename ELE, typename DATA,
    typename std::enable_if<
        (BuilderT::is_two_label_set_builder &&
         !std::is_same_v<DATA, std::tuple<grape::EmptyType>>)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele, data);
}

// insert for collectionBuilder
template <
    typename BuilderT, typename ELE, typename DATA,
    typename std::enable_if<(BuilderT::is_collection_builder)>::type* = nullptr>
static inline auto insert_into_builder_v2_impl(BuilderT& builder,
                                               const ELE& ele,
                                               const DATA& data) {
  return builder.Insert(ele);
}

// insert for adjEdgeSetBuilder
template <typename ELE, typename DATA, typename GI, typename LabelT,
          typename VID_T, typename... EDATA_T>
static inline auto insert_into_builder_v2_impl(
    AdjEdgeSetBuilder<GI, LabelT, VID_T, EDATA_T...>& builder, const ELE& ele,
    const DATA& data) {
  return builder.Insert(ele);
}

template <typename ELE, typename DATA, typename GI, typename LabelT,
          typename VID_T>
static inline auto insert_into_builder_v2_impl(
    AdjEdgeSetBuilder<GI, LabelT, VID_T, grape::EmptyType>& builder,
    const ELE& ele, const DATA& data) {
  return builder.Insert(ele);
}

// insert to single label edge label.
template <typename ELE, typename DATA, typename LabelT, typename VID_T,
          typename EDATA_T>
static inline auto insert_into_builder_v2_impl(
    SingleLabelEdgeSetBuilder<VID_T, LabelT, EDATA_T>& builder, const ELE& ele,
    const DATA& data) {
  return builder.Insert(ele);
}

}  // namespace gs

#endif  // ENGINES_HQPS_ENGINE_KEYED_UTILS_H_
