Mercurial > code
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C++/modules/Driver/Driver.h Sun Mar 08 14:26:33 2015 +0100 @@ -0,0 +1,529 @@ +/* + * 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_