OSDN Git Service

大量変更… (こういう風に書くのは好ましくない〜)
[gikomona/GikoMona.git] / core / include / database.hpp
index 795517d..161cd5a 100644 (file)
@@ -5,29 +5,44 @@
 
 #include <sqlite3.h>
 
+#include <boost/system/system_error.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/fusion/include/vector.hpp>
 
 #include "GikoMona.hpp"
 #include "query.hpp"
 
 namespace monazilla { namespace GikoMona { namespace core {
 
-class database final {
-public:
-    template <typename T>
-    class sql_executer final {
-        friend database;
+class database;
+
+template <typename ReturnTypeList, typename ArgTypeList>
+class sql_executer final {
+    friend database;
+    
+    typedef ReturnTypeList result_type;
+    typedef ArgTypeList arg_type;
+    typedef ::sqlite3 *db_object_type;
+    typedef ::sqlite3_stmt *sql_stmt_type;
+
+    const ::sqlite3_stmt *stmt;
         
-        sql_executer(const mona_string& sql) {}
-        ~sql_executer() {}
+    sql_executer(db_object_type db,
+                 const sql_stmt_type stmt,
+                 boost::system::error_code& ec) noexcept {}
+    ~sql_executer() {}
         
-    public:
-        void operator()() {}
-    };
+public:
+    typename <typename T>
+    void bind(const mona_string& param_name, const T& val) {}
+    result_type operator()() {}
+};
 
+class database final : public query {
 public:
     typedef ::sqlite3 *db_object_type;
     typedef database self_type;
+    typedef query base_type;
 
     database() : database("") {}
     
@@ -48,15 +63,14 @@ public:
     
     ~database() { close(); }
     
-    /// @brief 受け取った SQL を実行する。ただし、実行できる文は返り値の無いものに限られる。
+    /// @brief 受け取った SQL を実行する。ただし、実行できる文は引数と返り値が共に無いものに限られる。
     /**
      * @return SQL が正常に実行された場合は true、それ以外の場合は false を返す。
      * @note この関数は SQL の実行結果を返さない。したがって、実行結果が必要な場合は、
      *       compile_sql() を用いるべきである。
      */
     bool run_sql(const mona_string& sql) {
-        return (::sqlite3_exec(db, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK)
-            ? false : true;
+        return (::sqlite3_exec(db, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK);
     }
     
     /// @brief 受け取った SQL を sql_executer へと変換して返す。
@@ -65,23 +79,69 @@ public:
      *       実行した SQL の実行結果が不要である (あるいはそもそも実行結果が無い) 場合は、
      *       run_sql() を用いるべきである。
      */
-    template <typename T>
-    sql_executer<T> compile_sql(const mona_string& sql) {
-        return sql_executer<T>(sql);
+    template <typename ...T>
+    sql_executer<T...> compile_sql(const mona_string& sql) {
+        /**
+         *  @note sqlite3_prepare(db,zSql,nByte,ppStmtpzTail) で nByte に "sql.length() + 1" を
+         *        渡すのはなぜか?詳しくは次を参照 : http://www.sqlite.org/c3ref/prepare.html
+         *        ページ中程、"If the nByte argument is less than zero, ~" の先、関係あるところを
+         *        かいつまんで訳すと「もしも関数を呼び出した側が、zSql が NULL-terminated な文字列
+         *        (\0、\u0 が終端であるような文字列) であることを知っている場合、nByte に文字列のバイト長
+         *        (ただしここで言うバイト長には終端文字である\0または\u0も「含んだ」ものである) を渡すことで、
+         *        若干パフォーマンスが上がる」という記述がある。C++のstd::string::length()/size()は文字列の
+         *        終端文字を除いた長さを返すので、わざわざ1を加えている。
+         */
+        int result = ::sqlite3_prepare_v2(db.get_sqlite3_obj(),
+                                          sql.c_str(),
+                                          sql.length() + 1,
+                                          &stmt,
+                                          NULL);
+        if (result != ::SQLITE_OK && !stmt) {
+            
+        } else {
+            return sql_executer<T...>(sql);
+        }
     }
     
-    template <typename ...ValueType>
-    void insert(const mona_string& into,
-                const std::tuple<ValueType...>& value) {}
+    /**
+     *  @brief
+     *  @retval true insert 操作が成功した
+     *          false insert 操作に失敗した
+     *  @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
+     *                  記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
+     *  @param[in] value テーブルに対して代入する値を記述する。
+     *  @note さらに、最大限 multi-threading な環境を考慮しなければならない。
+     */
+    template <typename T, typename U, typename ...ValueType>
+    bool insert(const mona_string& into,
+                const boost::fusion::vector<T, U, ValueType...>& value) {}
+    
+    template <typename T>
+    bool insert(const mona_string& into,
+                const boost::fusion::vector<T>& value) {}
+    
+    template <typename T>
+    bool insert(const mona_string& into,
+                const boost::any& value,
+                base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
     
+    /**
+     *  @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+     *  @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
+     */
     template <typename T>
     T select(const mona_string& column,
              const mona_string& from) const noexcept {}
     
+    template <typename T>
+    boost::any select(const mona_string& column,
+                      const mona_string& from,
+                      base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
+    
     template <typename ...ValueType>
-    std::tuple<ValueType...>
+    boost::fusion::vector<ValueType...>
     select_all(const mona_string& from) const noexcept {}
-    
+
     /// @brief データベースの最適化を行う。
     /**
      * @note 内部では以下のコマンドが実行され、データベースの不要データの圧縮と再構築が行われる。
@@ -101,9 +161,7 @@ public:
             return is_opened_db;
         }
         
-        is_opened_db =
-            (::sqlite3_open(db_path.c_str(), &db) != SQLITE_OK)
-                ? false : true;
+        is_opened_db = (::sqlite3_open(db_path.c_str(), &db) != SQLITE_OK);
         
         return is_opened_db;
     }