1 #ifndef GIKOMONA_CORE_DATABASE_HPP
2 #define GIKOMONA_CORE_DATABASE_HPP
8 #include <boost/system/system_error.hpp>
9 #include <boost/filesystem.hpp>
10 #include <boost/fusion/include/vector.hpp>
12 #include "GikoMona.hpp"
15 namespace monazilla { namespace GikoMona { namespace core {
19 template <typename ReturnTypeList, typename ArgTypeList>
20 class sql_executer final {
23 typedef ReturnTypeList result_type;
24 typedef ArgTypeList arg_type;
25 typedef ::sqlite3 *db_object_type;
26 typedef ::sqlite3_stmt *sql_stmt_type;
28 const ::sqlite3_stmt *stmt;
30 sql_executer(db_object_type db,
31 const sql_stmt_type stmt,
32 boost::system::error_code& ec) noexcept {}
37 void bind(const mona_string& param_name, const T& val) {}
38 result_type operator()() {}
41 class database final : public query {
43 typedef ::sqlite3 *db_object_type;
44 typedef database self_type;
45 typedef query base_type;
47 database() : database("") {}
49 /// @brief すでに存在するデータベースファイルを開く。まだファイルが存在しない場合は、新たに作成する。
50 database(const boost::filesystem::path& db_path) {
54 if(!boost::filesystem::exists(db_path)) {
62 database(const self_type& other) = delete;
64 ~database() { close(); }
66 /// @brief 受け取った SQL を実行する。ただし、実行できる文は引数と返り値が共に無いものに限られる。
68 * @return SQL が正常に実行された場合は true、それ以外の場合は false を返す。
69 * @note この関数は SQL の実行結果を返さない。したがって、実行結果が必要な場合は、
70 * compile_sql() を用いるべきである。
72 bool run_sql(const mona_string& sql) {
73 return (::sqlite3_exec(db, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK);
76 /// @brief 受け取った SQL を sql_executer へと変換して返す。
78 * @note 返された sql_executer を実行することで、ここで渡した SQL の実行結果を得ることができる。
79 * 実行した SQL の実行結果が不要である (あるいはそもそも実行結果が無い) 場合は、
80 * run_sql() を用いるべきである。
82 template <typename ...T>
83 sql_executer<T...> compile_sql(const mona_string& sql) {
85 * @note sqlite3_prepare(db,zSql,nByte,ppStmtpzTail) で nByte に "sql.length() + 1" を
86 * 渡すのはなぜか?詳しくは次を参照 : http://www.sqlite.org/c3ref/prepare.html
87 * ページ中程、"If the nByte argument is less than zero, ~" の先、関係あるところを
88 * かいつまんで訳すと「もしも関数を呼び出した側が、zSql が NULL-terminated な文字列
89 * (\0、\u0 が終端であるような文字列) であることを知っている場合、nByte に文字列のバイト長
90 * (ただしここで言うバイト長には終端文字である\0または\u0も「含んだ」ものである) を渡すことで、
91 * 若干パフォーマンスが上がる」という記述がある。C++のstd::string::length()/size()は文字列の
92 * 終端文字を除いた長さを返すので、わざわざ1を加えている。
94 int result = ::sqlite3_prepare_v2(db.get_sqlite3_obj(),
99 if (result != ::SQLITE_OK && !stmt) {
102 return sql_executer<T...>(sql);
108 * @retval true insert 操作が成功した
109 * false insert 操作に失敗した
110 * @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
111 * 記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
112 * @param[in] value テーブルに対して代入する値を記述する。
113 * @note さらに、最大限 multi-threading な環境を考慮しなければならない。
115 template <typename T, typename U, typename ...ValueType>
116 bool insert(const mona_string& into,
117 const boost::fusion::vector<T, U, ValueType...>& value) {}
119 template <typename T>
120 bool insert(const mona_string& into,
121 const boost::fusion::vector<T>& value) {}
123 template <typename T>
124 bool insert(const mona_string& into,
125 const boost::any& value,
126 base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
129 * @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
130 * @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
132 template <typename T>
133 T select(const mona_string& column,
134 const mona_string& from) const noexcept {}
136 template <typename T>
137 boost::any select(const mona_string& column,
138 const mona_string& from,
139 base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
141 template <typename ...ValueType>
142 boost::fusion::vector<ValueType...>
143 select_all(const mona_string& from) const noexcept {}
145 /// @brief データベースの最適化を行う。
147 * @note 内部では以下のコマンドが実行され、データベースの不要データの圧縮と再構築が行われる。
155 /// @brief すでに存在するデータベースファイルを開く。
156 bool open(const boost::filesystem::path& db_path) {
159 } else if (!boost::filesystem::exists(db_path)) {
160 is_opened_db = false;
164 is_opened_db = (::sqlite3_open(db_path.c_str(), &db) != SQLITE_OK);
169 /// @brief まだ存在しないデータベースファイルを新たに作成する。
171 * @retval true ファイルが存在せず、かつ新たにデータベースファイルを作成することに成功した
172 * false ファイルが存在する、あるいは存在しないが新規データベースファイルの作成に失敗した
174 bool create(const boost::filesystem::path& db_path) {
175 if(boost::filesystem::exists(db_path)) {
179 return open(db_path);
182 /// @brief 開いていたデータベースファイルを閉じる。
183 void close() noexcept {
191 void begin_sql_statement() { run_sql("BEGIN;"); }
192 void end_sql_statement() { run_sql("END;"); }
196 struct is_responsible_to_query<database> : public boost::mpl::true_ {};