text: ////////////////////////////////////////////////////////////////////////////////
  /// DISCLAIMER
  ///
  /// Copyright 2018 ArangoDB GmbH, Cologne, Germany
  ///
  /// 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.
  ///
  /// Copyright holder is ArangoDB GmbH, Cologne, Germany
  ///
  /// @author Andrey Abramov
  /// @author Vasiliy Nabatchikov
  ////////////////////////////////////////////////////////////////////////////////
  
  #ifndef ARANGOD__VOCBASE__LOGICAL_DATA_SOURCE_H
  #define ARANGOD__VOCBASE__LOGICAL_DATA_SOURCE_H 1
  
  #include "Basics/Result.h"
  #include "voc-types.h"
  
  #include <velocypack/StringRef.h>
  
  struct TRI_vocbase_t;  // forward declaration
  
  namespace arangodb {
  
  namespace velocypack {
  class Builder;    // forward declaration
  }  // namespace velocypack
  
  ////////////////////////////////////////////////////////////////////////////////
  /// @brief a common ancestor to all database objects proving access to documents
  ///        e.g. LogicalCollection / LoigcalView
  ////////////////////////////////////////////////////////////////////////////////
  class LogicalDataSource {
   public:
    //////////////////////////////////////////////////////////////////////////////
    /// @brief singleton marker identifying the logical data-source category
    ///        each category is identity-compared for equivalence
    ///        e.g. static Category const& LogicalCollection::category()
    ///             static Category const& LogicalView::category()
    //////////////////////////////////////////////////////////////////////////////
    class Category final {
     public:
      Category() = default;
      Category(Category const&) = delete;
      Category(Category&&) = delete;
      Category& operator=(Category const&) = delete;
      Category& operator=(Category&&) = delete;
      bool operator==(Category const& other) const noexcept {
        return this == &other;
      }
      bool operator!=(Category const& other) const noexcept {
        return this != &other;
      }
      operator Category const*() const noexcept { return this; }
    };
  
    //////////////////////////////////////////////////////////////////////////////
    /// @brief singleton identifying the underlying implementation type
    ///        each implementation should have its own static instance
    ///        once a type is emplace(...)ed it cannot be removed
    //////////////////////////////////////////////////////////////////////////////
    class Type final {
     public:
      Type(Type&& other) noexcept = default;
      bool operator==(Type const& other) const noexcept { return this == &other; }
      bool operator!=(Type const& other) const noexcept { return this != &other; }
      operator Type const*() const noexcept { return this; }
      static Type const& emplace(arangodb::velocypack::StringRef const& name);
      std::string const& name() const noexcept { return _name; }
  
     private:
      std::string _name;  // type name for e.g. log messages
  
      Type() = default;
      Type(Type const&) = delete;
      Type& operator=(Type const&) = delete;
      Type& operator=(Type&&) noexcept = delete;
    };
  
    //////////////////////////////////////////////////////////////////////////////
    /// @brief constructor for a logical data-source taking configuration values
    ///        from 'definition'
    //////////////////////////////////////////////////////////////////////////////
    LogicalDataSource(Category const& category, Type const& type, TRI_vocbase_t& vocbase,
                      velocypack::Slice const& definition, uint64_t planVersion);
  
    //////////////////////////////////////////////////////////////////////////////
    /// @brief constructor for a logical data-source
    /// @note 'id' autogenerated IFF 'id' == 0
    /// @note 'planId' taken from evaluated value of 'id' IFF 'planId' == 0
    /// @note 'guid' autogenerated IFF 'guid'.empty()
    //////////////////////////////////////////////////////////////////////////////
    LogicalDataSource(Category const& category, Type const& type, TRI_vocbase_t& vocbase,
                      TRI_voc_cid_t id, std::string&& guid, TRI_voc_cid_t planId,
                      std::string&& name, uint64_t planVersion, bool system, bool deleted);
  
    LogicalDataSource(LogicalDataSource const& other)
        : _name(other._name),
          _category(other._category),
          _type(other._type),
          _vocbase(other._vocbase),
          _id(other._id),
          _planId(other._planId),
          _planVersion(other._planVersion),
          _guid(other._guid),
          _deleted(other._deleted),
          _system(other._system) {}
    
    LogicalDataSource& operator=(LogicalDataSource const& other) = delete;
  
    virtual ~LogicalDataSource() = default;
  
    Category const& category() const noexcept { return _category; }
    bool deleted() const noexcept { return _deleted; }
    virtual Result drop() = 0;
    std::string const& guid() const noexcept { return _guid; }
    TRI_voc_cid_t id() const noexcept { return _id; }
    std::string const& name() const noexcept { return _name; }
    TRI_voc_cid_t planId() const noexcept { return _planId; }
    uint64_t planVersion() const noexcept { return _planVersion; }
  
    enum class Serialize : uint8_t {
      // Include the basics for any given data source. Setting additonal flags
      // will only add additional information.
      Basics = 0,
      // Make output more detailed, e.g. for collections this will resolve CIDs
      // for 'distributeShardsLike', for views this will add view-specific
      // properties
      Detailed = 1,
      // This definition is meant to be persisted; will typically include
      // otherwise hidden internal properties
      ForPersistence = 2,
      // This will include any information about in-progress operations, such as
      // an index definition for an index being built in the background, which
      // would otherwise not be exposed yet
      IncludeInProgress = 4
    };
  
    /// @brief helper for building flags
    template <typename... Args>
    static inline constexpr std::underlying_type<Serialize>::type makeFlags(Serialize flag,
                                                                            Args... args) {
      return static_cast<std::underlying_type<Serialize>::type>(flag) + makeFlags(args...);
    }
  
    static inline constexpr std::underlying_type<Serialize>::type makeFlags() {
      return static_cast<std::underlying_type<Serialize>::type>(Serialize::Basics);
    }
  
    static inline constexpr bool hasFlag(std::underlying_type<Serialize>::type flags,
                                         Serialize aflag) {
      return (flags & static_cast<std::underlying_type<Serialize>::type>(aflag)) != 0;
    }
  
    //////////////////////////////////////////////////////////////////////////////
    /// @brief append a jSON definition of the data-source to the 'builder'
    /// @param the buffer to append to, must be an open object
    /// @param detailed make output more detailed, e.g.
    ///        for collections this will resolve CIDs for 'distributeShardsLike'
    ///        for views this will add view-specific properties
    /// @param forPersistence this definition is meant to be persisted
    /// @param inProgress this definition should include indices that are still
    ///                   in the process of being created
    /// @return success
    //////////////////////////////////////////////////////////////////////////////
    Result properties(velocypack::Builder& builder,
                      std::underlying_type<Serialize>::type flags) const;
  
    //////////////////////////////////////////////////////////////////////////////
    /// @brief updates properties of an existing DataSource
    /// @param definition the properties being updated
    /// @param partialUpdate modify only the specified properties (false == all)
    //////////////////////////////////////////////////////////////////////////////
    virtual Result properties(velocypack::Slice const& definition, bool partialUpdate) = 0;
  
    virtual Result rename(std::string&& newName) = 0;
    bool system() const noexcept { return _system; }
    Type const& type() const noexcept { return _type; }
    TRI_vocbase_t& vocbase() const noexcept { return _vocbase; }
  
   protected:
    //////////////////////////////////////////////////////////////////////////////
    /// @brief append implementation-specific values to the data-source definition
    //////////////////////////////////////////////////////////////////////////////
    virtual Result appendVelocyPack(velocypack::Builder&,
                                    std::underlying_type<Serialize>::type) const {
      return Result();  // NOOP by default
    }
  
    void deleted(bool deleted) noexcept { _deleted = deleted; }
    void name(std::string&& name) noexcept { _name = std::move(name); }
  
   private:
    // members ordered by sizeof(decltype(..)) except for '_guid'
    std::string _name;          // data-source name
    Category const& _category;  // the category of the logical data-source
    Type const& _type;  // the type of the underlying data-source implementation
    TRI_vocbase_t& _vocbase;      // the database where the data-source resides
    TRI_voc_cid_t const _id;      // local data-source id (current database node)
    TRI_voc_cid_t const _planId;  // global data-source id (cluster-wide)
    uint64_t const _planVersion;  // Only set if setPlanVersion was called. This only
                                  // happens in ClusterInfo when this object is used
                                  // to represent a cluster wide collection. This is
                                  // then the version in the agency Plan that underpins
                                  // the information in this object. Otherwise 0.
    std::string const _guid;  // globally unique data-source id (cluster-wide) for proper
                              // initialization must be positioned after '_name' and '_planId'
                              // since they are autogenerated
    bool _deleted;       // data-source marked as deleted
    bool const _system;  // this instance represents a system data-source
  };
  
  }  // namespace arangodb
  
  #endif  // ARANGOD__VOCBASE__LOGICAL_DATA_SOURCE_H
  