Mercurial > code
diff C++/Driver.h @ 214:6c49e5e3ecc8
Driver: now data is shared internally
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 25 Mar 2014 20:42:11 +0100 |
parents | d263f85f43a4 |
children | 1aceace80f61 |
line wrap: on
line diff
--- a/C++/Driver.h Mon Mar 24 13:54:28 2014 +0100 +++ b/C++/Driver.h Tue Mar 25 20:42:11 2014 +0100 @@ -1,7 +1,7 @@ /* * Driver.h -- generic SQL driver access * - * Copyright (c) 2013, David Demelier <markand@malikania.fr> + * 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 @@ -19,20 +19,19 @@ #ifndef _DRIVER_H_ #define _DRIVER_H_ -#include <iostream> +#include <ctime> #include <memory> #include <string> #include <unordered_map> - -#include "Date.h" +#include <type_traits> /** - * @enum ColumnType + * @enum DriverColumn * @brief The column type request * * Used for the drivers. */ -enum class ColumnType { +enum class DriverColumn { Invalid, //! not found Boolean, //! bool or 0 / 1 Date, //! date see Common/Date.h @@ -41,6 +40,9 @@ String, //! varchar to std::string }; +template <typename T> +struct DriverTypeInfo : std::false_type { }; + /** * @class Query * @brief Class for querying the database @@ -51,24 +53,101 @@ * * @see Driver::query */ -class Query { +class DriverQuery { public: - using Ptr = std::shared_ptr<Query>; + 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; - /** - * @class Error - * @brief Query exception on query error - */ - class Error : public std::exception { - private: - std::string m_error; + /** + * 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; - public: - Error(const std::string &error); + /** + * Tells how many number of columns are present for each + * row. + * + * @return the number of columns + */ + virtual int countColumns() = 0; - virtual const char *what() const throw(); + /** + * 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 @@ -79,59 +158,18 @@ * @param type * @throw Error on error */ - void assertRequest(int row, const std::string &column, ColumnType type); + void assertRequest(int row, const std::string &column, DriverColumn type); protected: - /** - * 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 Date 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; + Ptr m_impl; public: + DriverQuery(Ptr impl); + /** * Default destructor. */ - virtual ~Query(); + virtual ~DriverQuery(); /** * Get a variable from a row and column. @@ -149,7 +187,14 @@ * @throw Query::Error on error */ template <class T> - T get(int row, const std::string &column); + 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. @@ -157,14 +202,14 @@ * @param column the column name * @return the type */ - virtual ColumnType type(const std::string &column) const = 0; + DriverColumn type(const std::string &column) const; /** * Tells how many rows has been fetched. * * @return the number of rows */ - virtual int countRows() = 0; + int countRows(); /** * Tells how many number of columns are present for each @@ -172,7 +217,7 @@ * * @return the number of columns */ - virtual int countColumns() = 0; + int countColumns(); /** * Tells if the column is null or not. @@ -181,12 +226,12 @@ * @param column the column * @return an true if null */ - virtual bool isNull(int row, const std::string &column) = 0; + bool isNull(int row, const std::string &column); /** * Dump all rows and columns. */ - virtual void dump() = 0; + void dump(); }; /** @@ -195,74 +240,76 @@ * * This helps creating class with SQL injection security and such. */ -class Request { +class DriverRequest { public: - friend class Driver; + 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; - using Ptr = std::shared_ptr<Request>; + /** + * 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); -protected: - /** - * 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(Date value) = 0; - - /** - * Bind a double. - * - * @param value the double - * @return the string to use - */ - virtual std::string bindDouble(double value) = 0; +public: + DriverRequest(Ptr impl, const std::string &command); /** - * Bind an integer. - * - * @param value the integer - * @return the string to use - */ - virtual std::string bindInt(int value) = 0; - - /** - * Bind a string. - * - * @param value the string - * @return the string to use - */ - virtual std::string bindString(std::string value) = 0; - - /** - * Default constructor with SQL command. - * - * @param command the SQL command - */ - Request(const std::string &command); - -public: - /** * Default destructor. */ - virtual ~Request(); + virtual ~DriverRequest(); /** * Bind a value. @@ -270,7 +317,12 @@ * @param value the value */ template <typename T> - void bind(T value); + void bind(T value) + { + static_assert(DriverTypeInfo<T>::value, "unsupported type"); + + setValue(DriverTypeInfo<T>::bind(value)); + } /** * Convert the request to string. @@ -288,46 +340,66 @@ * does not include any DBMS code and just call virtual functions for * a simpler integration of new DBMS drivers. */ -class Driver : public std::enable_shared_from_this<Driver> { -protected: - std::string m_error; +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; - /** - * Default constructor. Should not be used. - * - * @see Driver::create - */ - Driver(); + /** + * 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: - using Params = std::unordered_map<std::string, std::string>; - using Ptr = std::shared_ptr<Driver>; - - /** - * Create a new Driver object, some queries need to do additional - * internal requests so it's easier to use shared_ptr. - * - * @return a shared_ptr - */ - template <class T> - static Ptr create() - { - T *t = new T(); - - return std::shared_ptr<T>(t); - } + Driver() = default; /** * Virtual destructor. */ - virtual ~Driver(); - - /** - * Get the error. - * - * @return the error - */ - const std::string &getError() const; + virtual ~Driver() = default; /** * Wrapper for std::string variant. @@ -336,7 +408,7 @@ * @return a result * @throw Query::Error on failure */ - Query::Ptr query(Request::Ptr request); + DriverQuery query(DriverRequest request); /** * Create a synchronous connection, it waits and block until @@ -344,7 +416,7 @@ * * @param params a list of parameters. */ - virtual bool connect(const Params ¶ms) = 0; + void connect(const Params ¶ms); /** * Prepare a request with the specified SQL command. @@ -353,7 +425,7 @@ * @return a request to use with query * @see query */ - virtual Request::Ptr prepare(const std::string &command) = 0; + DriverRequest prepare(const std::string &command); /** * Execute a query. @@ -362,21 +434,97 @@ * @return a result * @throw Query::Error on failure */ - virtual Query::Ptr query(const std::string &command) = 0; + DriverQuery query(const std::string &command); /** * Get the driver connection description. * * @return the description */ - virtual std::string description() const = 0; + std::string description() const; /** * Get the driver version as a string. * * @return the version */ - virtual std::string version() const = 0; + 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_