view C++/Driver.h @ 196:274b4f216e65

DynLib: Windows support complete
author David Demelier <markand@malikania.fr>
date Thu, 28 Nov 2013 20:03:07 +0100
parents d263f85f43a4
children 6c49e5e3ecc8
line wrap: on
line source

/*
 * Driver.h -- generic SQL driver access
 *
 * Copyright (c) 2013, 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 <iostream>
#include <memory>
#include <string>
#include <unordered_map>

#include "Date.h"

/**
 * @enum ColumnType
 * @brief The column type request
 *
 * Used for the drivers.
 */
enum class ColumnType {
	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
};

/**
 * @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 Query {
public:
	using Ptr = std::shared_ptr<Query>;

	/**
	 * @class Error
	 * @brief Query exception on query error
	 */
	class Error : public std::exception {
	private:
		std::string m_error;

	public:
		Error(const std::string &error);

		virtual const char *what() const throw();
	};

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, ColumnType 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;

public:
	/**
	 * Default destructor.
	 */
	virtual ~Query();

	/**
	 * 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);

	/**
	 * Returns the type of a named column.
	 *
	 * @param column the column name
	 * @return the type
	 */
	virtual ColumnType 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;
};

/**
 * @class Request
 * @brief A secure helper for creating requests
 *
 * This helps creating class with SQL injection security and such.
 */
class Request {
public:
	friend class Driver;

	using Ptr	= std::shared_ptr<Request>;

private:
	size_t		m_pos;
	int		m_params;
	std::string	m_command;

	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;

	/**
	 * 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();

	/**
	 * Bind a value.
	 *
	 * @param value the value
	 */
	template <typename T>
	void bind(T 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 std::enable_shared_from_this<Driver> {
protected:
	std::string m_error;

	/**
	 * Default constructor. Should not be used.
	 *
	 * @see Driver::create
	 */
	Driver();

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);
	}

	/**
	 * Virtual destructor.
	 */
	virtual ~Driver();

	/**
	 * Get the error.
	 *
	 * @return the error
	 */
	const std::string &getError() const;

	/**
	 * Wrapper for std::string variant.
	 *
	 * @param request the request to use
	 * @return a result
	 * @throw Query::Error on failure
	 */
	Query::Ptr query(Request::Ptr 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.
	 */
	virtual bool 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 Request::Ptr prepare(const std::string &command) = 0;

	/**
	 * Execute a query.
	 *
	 * @param query the SQL command
	 * @return a result
	 * @throw Query::Error on failure
	 */
	virtual Query::Ptr 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;
};

#endif // !_DRIVER_H_