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 &params) = 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 &params);
+
+	/**
+	 * 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_