text: #pragma once
  
  #include <string>   //  std::string
  
  namespace sqlite_orm {
      
      namespace internal {
          
          /**
           *  DISCTINCT generic container.
           */
          template<class T>
          struct distinct_t {
              T t;
              
              operator std::string() const {
                  return "DISTINCT";
              }
          };
          
          /**
           *  ALL generic container.
           */
          template<class T>
          struct all_t {
              T t;
              
              operator std::string() const {
                  return "ALL";
              }
          };
          
          template<class ...Args>
          struct columns_t {
              bool distinct = false;
              
              template<class L>
              void for_each(L) const {
                  //..
              }
              
              int count() const {
                  return 0;
              }
          };
          
          template<class T, class ...Args>
          struct columns_t<T, Args...> : public columns_t<Args...> {
              T m;
              
              columns_t(decltype(m) m_, Args&& ...args): super(std::forward<Args>(args)...), m(m_) {}
              
              template<class L>
              void for_each(L l) const {
                  l(this->m);
                  this->super::for_each(l);
              }
              
              int count() const {
                  return 1 + this->super::count();
              }
          private:
              using super = columns_t<Args...>;
          };
          
          template<class ...Args>
          struct set_t {
              
              operator std::string() const {
                  return "SET";
              }
              
              template<class F>
              void for_each(F) {
                  //..
              }
          };
          
          template<class L, class ...Args>
          struct set_t<L, Args...> : public set_t<Args...> {
              static_assert(is_assign_t<typename std::remove_reference<L>::type>::value, "set_t argument must be assign_t");
              
              L l;
              
              using super = set_t<Args...>;
              using self = set_t<L, Args...>;
              
              set_t(L l_, Args&& ...args) : super(std::forward<Args>(args)...), l(std::forward<L>(l_)) {}
              
              template<class F>
              void for_each(F f) {
                  f(l);
                  this->super::for_each(f);
              }
          };
          
          /**
           *  This class is used to store explicit mapped type T and its column descriptor (member pointer/getter/setter).
           *  Is useful when mapped type is derived from other type and base class has members mapped to a storage.
           */
          template<class T, class F>
          struct column_pointer {
              using type = T;
              using field_type = F;
              
              field_type field;
          };
          
          /**
           *  Subselect object type.
           */
          template<class T, class ...Args>
          struct select_t {
              using return_type = T;
              using conditions_type = std::tuple<Args...>;
              
              return_type col;
              conditions_type conditions;
          };
          
          /**
           *  Union object type.
           */
          template<class L, class R>
          struct union_t {
              using left_type = L;
              using right_type = R;
              
              left_type left;
              right_type right;
              bool all = false;
              
              union_t(left_type l, right_type r, decltype(all) all_): left(std::move(l)), right(std::move(r)), all(all_) {}
              
              union_t(left_type l, right_type r): left(std::move(l)), right(std::move(r)) {}
  
              operator std::string() const {
                  if(!this->all){
                      return "UNION";
                  }else{
                      return "UNION ALL";
                  }
              }
          };
          
          /**
           *  Generic way to get DISTINCT value from any type.
           */
          template<class T>
          bool get_distinct(const T &t) {
              return false;
          }
          
          template<class ...Args>
          bool get_distinct(const columns_t<Args...> &cols) {
              return cols.distinct;
          }
      }
      
      template<class T>
      internal::distinct_t<T> distinct(T t) {
          return {t};
      }
      
      template<class T>
      internal::all_t<T> all(T t) {
          return {t};
      }
      
      template<class ...Args>
      internal::columns_t<Args...> distinct(internal::columns_t<Args...> cols) {
          cols.distinct = true;
          return cols;
      }
      
      /**
       *  SET keyword used in UPDATE ... SET queries.
       *  Args must have `assign_t` type. E.g. set(assign(&User::id, 5)) or set(c(&User::id) = 5)
       */
      template<class ...Args>
      internal::set_t<Args...> set(Args&& ...args) {
          return {std::forward<Args>(args)...};
      }
      
      template<class ...Args>
      internal::columns_t<Args...> columns(Args&& ...args) {
          return {std::forward<Args>(args)...};
      }
      
      /**
       *  Use it like this:
       *  struct MyType : BaseType { ... };
       *  storage.select(column<MyType>(&BaseType::id));
       */
      template<class T, class F>
      internal::column_pointer<T, F> column(F f) {
          return {f};
      }
      
      /**
       *  Public function for subselect query. Is useful in UNION queries.
       */
      template<class T, class ...Args>
      internal::select_t<T, Args...> select(T t, Args ...args) {
          return {std::move(t), std::make_tuple<Args...>(std::forward<Args>(args)...)};
      }
      
      /**
       *  Public function for UNION operator.
       *  lhs and rhs are subselect objects.
       *  Look through example in examples/union.cpp
       */
      template<class L, class R>
      internal::union_t<L, R> union_(L lhs, R rhs) {
          return {std::move(lhs), std::move(rhs)};
      }
      
      /**
       *  Public function for UNION ALL operator.
       *  lhs and rhs are subselect objects.
       *  Look through example in examples/union.cpp
       */
      template<class L, class R>
      internal::union_t<L, R> union_all(L lhs, R rhs) {
          return {std::move(lhs), std::move(rhs), true};
      }
  }
  