#pragma once
#include <drogon/exports.h>
#include <functional>
#include <stdexcept>
#include <string>
namespace drogon
{
namespace orm
{
class DROGON_EXPORT DrogonDbException
{
  public:
    virtual ~DrogonDbException() noexcept
    {
    }
    virtual const std::exception &base() const noexcept
    {
        static std::exception except;
        return except;
    }  
};
class Failure : public DrogonDbException, public std::runtime_error
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit Failure(const std::string &);
};
class BrokenConnection : public Failure
{
  public:
    DROGON_EXPORT BrokenConnection();
    DROGON_EXPORT explicit BrokenConnection(const std::string &);
};
class SqlError : public Failure
{
    const std::string query_;
    const std::string sqlState_;
    const int errcode_{0};
    const int extendedErrcode_{0};
  public:
    DROGON_EXPORT explicit SqlError(const std::string &msg = "",
                                    const std::string &Q = "",
                                    const char sqlstate[] = nullptr);
    DROGON_EXPORT explicit SqlError(const std::string &msg,
                                    const std::string &Q,
                                    const int errcode,
                                    const int extendedErrcode);
    DROGON_EXPORT virtual ~SqlError() noexcept;
    DROGON_EXPORT const std::string &query() const noexcept;
    DROGON_EXPORT const std::string &sqlState() const noexcept;
    DROGON_EXPORT int errcode() const noexcept;
    DROGON_EXPORT int extendedErrcode() const noexcept;
};
class InDoubtError : public Failure
{
  public:
    DROGON_EXPORT explicit InDoubtError(const std::string &);
};
class TransactionRollback : public Failure
{
  public:
    DROGON_EXPORT explicit TransactionRollback(const std::string &);
};
class SerializationFailure : public TransactionRollback
{
  public:
    DROGON_EXPORT explicit SerializationFailure(const std::string &);
};
class StatementCompletionUnknown : public TransactionRollback
{
  public:
    DROGON_EXPORT explicit StatementCompletionUnknown(const std::string &);
};
class DeadlockDetected : public TransactionRollback
{
  public:
    DROGON_EXPORT explicit DeadlockDetected(const std::string &);
};
class InternalError : public DrogonDbException, public std::logic_error
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit InternalError(const std::string &);
};
class TimeoutError : public DrogonDbException, public std::logic_error
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit TimeoutError(const std::string &);
};
class UsageError : public DrogonDbException, public std::logic_error
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit UsageError(const std::string &);
};
class ArgumentError : public DrogonDbException, public std::invalid_argument
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit ArgumentError(const std::string &);
};
class ConversionError : public DrogonDbException, public std::domain_error
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit ConversionError(const std::string &);
};
class RangeError : public DrogonDbException, public std::out_of_range
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    DROGON_EXPORT explicit RangeError(const std::string &);
};
class UnexpectedRows : public RangeError
{
    const std::exception &base() const noexcept override
    {
        return *this;
    }
  public:
    explicit UnexpectedRows(const std::string &msg) : RangeError(msg)
    {
    }
};
class FeatureNotSupported : public SqlError
{
  public:
    explicit FeatureNotSupported(const std::string &err,
                                 const std::string &Q = "",
                                 const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit FeatureNotSupported(const std::string &msg,
                                 const std::string &Q,
                                 const int errcode,
                                 const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class DataException : public SqlError
{
  public:
    explicit DataException(const std::string &err,
                           const std::string &Q = "",
                           const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit DataException(const std::string &msg,
                           const std::string &Q,
                           const int errcode,
                           const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class IntegrityConstraintViolation : public SqlError
{
  public:
    explicit IntegrityConstraintViolation(const std::string &err,
                                          const std::string &Q = "",
                                          const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit IntegrityConstraintViolation(const std::string &msg,
                                          const std::string &Q,
                                          const int errcode,
                                          const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class RestrictViolation : public IntegrityConstraintViolation
{
  public:
    explicit RestrictViolation(const std::string &err,
                               const std::string &Q = "",
                               const char sqlstate[] = nullptr)
        : IntegrityConstraintViolation(err, Q, sqlstate)
    {
    }
    explicit RestrictViolation(const std::string &msg,
                               const std::string &Q,
                               const int errcode,
                               const int extendedErrcode)
        : IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
    {
    }
};
class NotNullViolation : public IntegrityConstraintViolation
{
  public:
    explicit NotNullViolation(const std::string &err,
                              const std::string &Q = "",
                              const char sqlstate[] = nullptr)
        : IntegrityConstraintViolation(err, Q, sqlstate)
    {
    }
    explicit NotNullViolation(const std::string &msg,
                              const std::string &Q,
                              const int errcode,
                              const int extendedErrcode)
        : IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
    {
    }
};
class ForeignKeyViolation : public IntegrityConstraintViolation
{
  public:
    explicit ForeignKeyViolation(const std::string &err,
                                 const std::string &Q = "",
                                 const char sqlstate[] = nullptr)
        : IntegrityConstraintViolation(err, Q, sqlstate)
    {
    }
    explicit ForeignKeyViolation(const std::string &msg,
                                 const std::string &Q,
                                 const int errcode,
                                 const int extendedErrcode)
        : IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
    {
    }
};
class UniqueViolation : public IntegrityConstraintViolation
{
  public:
    explicit UniqueViolation(const std::string &err,
                             const std::string &Q = "",
                             const char sqlstate[] = nullptr)
        : IntegrityConstraintViolation(err, Q, sqlstate)
    {
    }
    explicit UniqueViolation(const std::string &msg,
                             const std::string &Q,
                             const int errcode,
                             const int extendedErrcode)
        : IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
    {
    }
};
class CheckViolation : public IntegrityConstraintViolation
{
  public:
    explicit CheckViolation(const std::string &err,
                            const std::string &Q = "",
                            const char sqlstate[] = nullptr)
        : IntegrityConstraintViolation(err, Q, sqlstate)
    {
    }
    explicit CheckViolation(const std::string &msg,
                            const std::string &Q,
                            const int errcode,
                            const int extendedErrcode)
        : IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
    {
    }
};
class InvalidCursorState : public SqlError
{
  public:
    explicit InvalidCursorState(const std::string &err,
                                const std::string &Q = "",
                                const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit InvalidCursorState(const std::string &msg,
                                const std::string &Q,
                                const int errcode,
                                const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class InvalidSqlStatementName : public SqlError
{
  public:
    explicit InvalidSqlStatementName(const std::string &err,
                                     const std::string &Q = "",
                                     const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit InvalidSqlStatementName(const std::string &msg,
                                     const std::string &Q,
                                     const int errcode,
                                     const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class InvalidCursorName : public SqlError
{
  public:
    explicit InvalidCursorName(const std::string &err,
                               const std::string &Q = "",
                               const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit InvalidCursorName(const std::string &msg,
                               const std::string &Q,
                               const int errcode,
                               const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class SyntaxError : public SqlError
{
  public:
    const int errorPosition_;
    explicit SyntaxError(const std::string &err,
                         const std::string &Q = "",
                         const char sqlstate[] = nullptr,
                         int pos = -1)
        : SqlError(err, Q, sqlstate), errorPosition_(pos)
    {
    }
    explicit SyntaxError(const std::string &msg,
                         const std::string &Q,
                         const int errcode,
                         const int extendedErrcode,
                         int pos = -1)
        : SqlError(msg, Q, errcode, extendedErrcode), errorPosition_(pos)
    {
    }
};
class UndefinedColumn : public SyntaxError
{
  public:
    explicit UndefinedColumn(const std::string &err,
                             const std::string &Q = "",
                             const char sqlstate[] = nullptr)
        : SyntaxError(err, Q, sqlstate)
    {
    }
    explicit UndefinedColumn(const std::string &msg,
                             const std::string &Q,
                             const int errcode,
                             const int extendedErrcode)
        : SyntaxError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class UndefinedFunction : public SyntaxError
{
  public:
    explicit UndefinedFunction(const std::string &err,
                               const std::string &Q = "",
                               const char sqlstate[] = nullptr)
        : SyntaxError(err, Q, sqlstate)
    {
    }
    explicit UndefinedFunction(const std::string &msg,
                               const std::string &Q,
                               const int errcode,
                               const int extendedErrcode)
        : SyntaxError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class UndefinedTable : public SyntaxError
{
  public:
    explicit UndefinedTable(const std::string &err,
                            const std::string &Q = "",
                            const char sqlstate[] = nullptr)
        : SyntaxError(err, Q, sqlstate)
    {
    }
    explicit UndefinedTable(const std::string &msg,
                            const std::string &Q,
                            const int errcode,
                            const int extendedErrcode)
        : SyntaxError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class InsufficientPrivilege : public SqlError
{
  public:
    explicit InsufficientPrivilege(const std::string &err,
                                   const std::string &Q = "",
                                   const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit InsufficientPrivilege(const std::string &msg,
                                   const std::string &Q,
                                   const int errcode,
                                   const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class InsufficientResources : public SqlError
{
  public:
    explicit InsufficientResources(const std::string &err,
                                   const std::string &Q = "",
                                   const char sqlstate[] = nullptr)
        : SqlError(err, Q, sqlstate)
    {
    }
    explicit InsufficientResources(const std::string &msg,
                                   const std::string &Q,
                                   const int errcode,
                                   const int extendedErrcode)
        : SqlError(msg, Q, errcode, extendedErrcode)
    {
    }
};
class DiskFull : public InsufficientResources
{
  public:
    explicit DiskFull(const std::string &err,
                      const std::string &Q = "",
                      const char sqlstate[] = nullptr)
        : InsufficientResources(err, Q, sqlstate)
    {
    }
    explicit DiskFull(const std::string &msg,
                      const std::string &Q,
                      const int errcode,
                      const int extendedErrcode)
        : InsufficientResources(msg, Q, errcode, extendedErrcode)
    {
    }
};
class OutOfMemory : public InsufficientResources
{
  public:
    explicit OutOfMemory(const std::string &err,
                         const std::string &Q = "",
                         const char sqlstate[] = nullptr)
        : InsufficientResources(err, Q, sqlstate)
    {
    }
    explicit OutOfMemory(const std::string &msg,
                         const std::string &Q,
                         const int errcode,
                         const int extendedErrcode)
        : InsufficientResources(msg, Q, errcode, extendedErrcode)
    {
    }
};
class TooManyConnections : public BrokenConnection
{
  public:
    explicit TooManyConnections(const std::string &err) : BrokenConnection(err)
    {
    }
};
using DrogonDbExceptionCallback =
    std::function<void(const DrogonDbException &)>;
}  
}  