// Copyright (C) 2011  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_SQLiTE_TOOLS_H_
#define DLIB_SQLiTE_TOOLS_H_


#include "sqlite_tools_abstract.h"
#include "sqlite.h"

// ----------------------------------------------------------------------------------------

namespace dlib
{

    class transaction : noncopyable
    {
    public:
        transaction (
            database& db_
        ) :
            db(db_),
            committed(false)
        {
            db.exec("begin transaction");
        }

        void commit ()
        {
            if (!committed)
            {
                committed = true;
                db.exec("commit");
            }
        }

        ~transaction() noexcept(false)
        {
            if (!committed)
                db.exec("rollback");
        }

    private:
        database& db;
        bool committed;

    };

// ----------------------------------------------------------------------------------------


    template <
        typename T
        >
    void query_object (
        database& db,
        const std::string& query,
        T& item
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            st.get_column_as_object(0,item);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

    inline std::string query_text (
        database& db,
        const std::string& query
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            const std::string& temp = st.get_column_as_text(0);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
            return temp;
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

    inline double query_double (
        database& db,
        const std::string& query
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            double temp = st.get_column_as_double(0);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
            return temp;
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

    inline int query_int (
        database& db,
        const std::string& query
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            int temp = st.get_column_as_int(0);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
            return temp;
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

    inline int64 query_int64 (
        database& db,
        const std::string& query
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            int64 temp = st.get_column_as_int64(0);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
            return temp;
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

    inline const std::vector<char> query_blob (
        database& db,
        const std::string& query
    )
    {
        statement st(db, query);
        st.exec();
        if (st.move_next() && st.get_num_columns() == 1)
        {
            const std::vector<char>& temp = st.get_column_as_blob(0);
            if (st.move_next())
                throw sqlite_error("query doesn't result in exactly 1 element");
            return temp;
        }
        else
        {
            throw sqlite_error("query doesn't result in exactly 1 element");
        }
    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_SQLiTE_TOOLS_H_