Mercurial > code
view C++/modules/Driver/Driver.h @ 334:0b576ee64d45
* Create brand new hierarchy
* Rename DynLib to Dynlib
* Remove some warnings
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 08 Mar 2015 14:26:33 +0100 |
parents | C++/Driver.h@1aceace80f61 |
children |
line wrap: on
line source
/* * Driver.h -- generic SQL driver access * * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _DRIVER_H_ #define _DRIVER_H_ #include <ctime> #include <memory> #include <string> #include <unordered_map> #include <type_traits> /** * @enum DriverColumn * @brief The column type request * * Used for the drivers. */ enum class DriverColumn { Invalid, //! not found Boolean, //! bool or 0 / 1 Date, //! date see Common/Date.h Double, //! double Integer, //! 32 or 64 bit int String, //! varchar to std::string }; template <typename T> struct DriverTypeInfo : std::false_type { }; /** * @class Query * @brief Class for querying the database * * That class is returned when a SQL query succeed. It can retrieve the * number of rows, columns and retrieve the results independantly from the * driver. * * @see Driver::query */ class DriverQuery { public: friend struct DriverTypeInfo<bool>; friend struct DriverTypeInfo<time_t>; friend struct DriverTypeInfo<double>; friend struct DriverTypeInfo<int>; friend struct DriverTypeInfo<std::string>; class Impl { public: /** * Get a bool. * * @param row the row number * @param column the column * @return the value */ virtual bool getBoolean(int row, const std::string &column) = 0; /** * Get a Date. * * @param row the row number * @param column the column * @return the value */ virtual time_t getDate(int row, const std::string &column) = 0; /** * Get a double. * * @param row the row number * @param column the column * @return the value */ virtual double getDouble(int row, const std::string &column) = 0; /** * Get a integer. * * @param row the row number * @param column the column * @return the value */ virtual int getInt(int row, const std::string &column) = 0; /** * Get a string. * * @param row the row number * @param column the column * @return the value */ virtual std::string getString(int row, const std::string &column) = 0; /** * Returns the type of a named column. * * @param column the column name * @return the type */ virtual DriverColumn type(const std::string &column) const = 0; /** * Tells how many rows has been fetched. * * @return the number of rows */ virtual int countRows() = 0; /** * Tells how many number of columns are present for each * row. * * @return the number of columns */ virtual int countColumns() = 0; /** * Tells if the column is null or not. * * @param row the row number * @param column the column * @return an true if null */ virtual bool isNull(int row, const std::string &column) = 0; /** * Dump all rows and columns. */ virtual void dump() = 0; }; using Ptr = std::shared_ptr<Impl>; private: /** * Check if the request is valid and throws an exception * on error. * * @param row the row number * @param column the column name * @param type * @throw Error on error */ void assertRequest(int row, const std::string &column, DriverColumn type); protected: Ptr m_impl; public: DriverQuery(Ptr impl); /** * Default destructor. */ virtual ~DriverQuery(); /** * Get a variable from a row and column. * * Specialization available: * - bool * - Date * - double * - int * - std::string * * @param row the row number (starts from 0) * @param column the the column name * @return the value * @throw Query::Error on error */ template <class T> T get(int row, const std::string &column) { static_assert(DriverTypeInfo<T>::value, "unsupported type"); assertRequest(row, column, DriverTypeInfo<T>::type); return DriverTypeInfo<T>::get(*this, row, column); } /** * Returns the type of a named column. * * @param column the column name * @return the type */ DriverColumn type(const std::string &column) const; /** * Tells how many rows has been fetched. * * @return the number of rows */ int countRows(); /** * Tells how many number of columns are present for each * row. * * @return the number of columns */ int countColumns(); /** * Tells if the column is null or not. * * @param row the row number * @param column the column * @return an true if null */ bool isNull(int row, const std::string &column); /** * Dump all rows and columns. */ void dump(); }; /** * @class Request * @brief A secure helper for creating requests * * This helps creating class with SQL injection security and such. */ class DriverRequest { public: friend struct DriverTypeInfo<bool>; friend struct DriverTypeInfo<time_t>; friend struct DriverTypeInfo<double>; friend struct DriverTypeInfo<int>; friend struct DriverTypeInfo<std::string>; class Impl { public: /** * Bind a boolean. * * @param value the boolean * @return the string to use */ virtual std::string bindBoolean(bool value) = 0; /** * Bind a date. * * @param value the date * @return the string to use */ virtual std::string bindDate(time_t value) = 0; /** * Bind a double. * * @param value the double * @return the string to use */ virtual std::string bindDouble(double value) = 0; /** * Bind an integer. * * @param value the integer * @return the string to use */ virtual std::string bindInteger(int value) = 0; /** * Bind a string. * * @param value the string * @return the string to use */ virtual std::string bindString(std::string value) = 0; }; using Ptr = std::shared_ptr<Impl>; private: size_t m_pos; int m_params; std::string m_command; Ptr m_impl; void assertCorrect(); void setValue(const std::string &value); public: DriverRequest(Ptr impl, const std::string &command); /** * Default destructor. */ virtual ~DriverRequest(); /** * Bind a value. * * @param value the value */ template <typename T> void bind(T value) { static_assert(DriverTypeInfo<T>::value, "unsupported type"); setValue(DriverTypeInfo<T>::bind(value)); } /** * Convert the request to string. * * @return the request as a string */ operator std::string(); }; /** * @class Driver * @brief A generic SQL driver * * This class is used to connect to a database and execute SQL queries. It * does not include any DBMS code and just call virtual functions for * a simpler integration of new DBMS drivers. */ class Driver { public: class Impl; using Params = std::unordered_map<std::string, std::string>; using Ptr = std::shared_ptr<Impl>; class Impl { public: /** * Create a synchronous connection, it waits and block until * the connection is made up to a specified timeout max. * * @param params a list of parameters. */ virtual void connect(const Params ¶ms) = 0; /** * Prepare a request with the specified SQL command. * * @param command the SQL command to parse and bind * @return a request to use with query * @see query */ virtual DriverRequest prepare(const std::string &command) = 0; /** * Execute a query. * * @param query the SQL command * @return a result * @throw Query::Error on failure */ virtual DriverQuery query(const std::string &command) = 0; /** * Get the driver connection description. * * @return the description */ virtual std::string description() const = 0; /** * Get the driver version as a string. * * @return the version */ virtual std::string version() const = 0; }; protected: Ptr m_impl; public: Driver() = default; /** * Virtual destructor. */ virtual ~Driver() = default; /** * Wrapper for std::string variant. * * @param request the request to use * @return a result * @throw Query::Error on failure */ DriverQuery query(DriverRequest request); /** * Create a synchronous connection, it waits and block until * the connection is made up to a specified timeout max. * * @param params a list of parameters. */ void connect(const Params ¶ms); /** * Prepare a request with the specified SQL command. * * @param command the SQL command to parse and bind * @return a request to use with query * @see query */ DriverRequest prepare(const std::string &command); /** * Execute a query. * * @param query the SQL command * @return a result * @throw Query::Error on failure */ DriverQuery query(const std::string &command); /** * Get the driver connection description. * * @return the description */ std::string description() const; /** * Get the driver version as a string. * * @return the version */ std::string version() const; }; template <> struct DriverTypeInfo<bool> : std::true_type { static const DriverColumn type = DriverColumn::Boolean; static bool get(DriverQuery &query, int row, const std::string &column) { return query.m_impl->getBoolean(row, column); } static void bind(DriverRequest &request, bool value) { request.m_impl->bindBoolean(value); } }; template <> struct DriverTypeInfo<time_t> : std::true_type { static const DriverColumn type = DriverColumn::Date; static time_t get(DriverQuery &query, int row, const std::string &column) { return query.m_impl->getDate(row, column); } static void bind(DriverRequest &request, time_t value) { request.m_impl->bindDate(value); } }; template <> struct DriverTypeInfo<double> : std::true_type { static const DriverColumn type = DriverColumn::Double; static double get(DriverQuery &query, int row, const std::string &column) { return query.m_impl->getDouble(row, column); } static void bind(DriverRequest &request, double value) { request.m_impl->bindDouble(value); } }; template <> struct DriverTypeInfo<int> : std::true_type { static const DriverColumn type = DriverColumn::Integer; static int get(DriverQuery &query, int row, const std::string &column) { return query.m_impl->getInt(row, column); } static void bind(DriverRequest &request, int value) { request.m_impl->bindInteger(value); } }; template <> struct DriverTypeInfo<std::string> : std::true_type { static const DriverColumn type = DriverColumn::String; static std::string get(DriverQuery &query, int row, const std::string &column) { return query.m_impl->getString(row, column); } static void bind(DriverRequest &request, const std::string &value) { request.m_impl->bindString(value); } }; #endif // !_DRIVER_H_