僕はよく C++ 用の SQLite3 ライブラリを探し歩いていて、見つけるたびに「1行掲示板」を実装してみている。
ウェブサーバは crow というライブラリを使い、SQLite3 の部分だけ差し替えて試すという感じ。初代は MySQL 用に作った。
GitHub - mattn/crow-bbs
https://github.com/mattn/crow-bbs
これを SQLite3 向けに直したのが crow-bbs-sqlite3
GitHub - mattn/crow-bbs-sqlite3
https://github.com/mattn/crow-bbs-sqlite3
さらにそれを sqlpp11 向けに直したのが crow-bbs-sqlite3-sqlpp11
GitHub - mattn/crow-bbs-sqlite3-sqlpp11
https://github.com/mattn/crow-bbs-sqlite3-sqlpp11
sqlpp11 は SQLite3 専用という訳ではなく、connector を使って異なる RDBMS も扱える。
先日、C++ 用 SQLite3 ORM の sqlite_orm を見つけたのでこれも試してみた。
GitHub - fnc12/sqlite_orm: ❤️ SQLite ORM light header only library for modern C++
// SELECT AVG(id) FROM users auto averageId = storage.avg(&User::id); cout << " averageId = " << ave...
https://github.com/fnc12/sqlite_orm
作った物はこちら。
GitHub - mattn/crow-bbs-sqlite3-sqlite_orm
https://github.com/mattn/crow-bbs-sqlite3-sqlite_orm
sqlite_orm は SQLite3 専用ではあるものの、sqlite3 ネイティブライブラリの様に SQLite3 色が濃くなく、sqlpp11 の様に SQL も登場しない。初回のスキーマ構築で struct との bind を行う。
struct Post {
int id;
std::string text;
std::string created;
};
auto storage = sqlite_orm::make_storage("bbs.db",
sqlite_orm::make_table("bbs",
sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),
sqlite_orm::make_column("text", &Post::text),
sqlite_orm::make_column("created", &Post::created)
));
storage.sync_schema();
全ての Post を得るのであれば1行で出来る。
auto posts = storage.get_all<Post>();
追加も簡単
Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now", "localtime")).front()};
storage.insert(post);
1行掲示板くらいのアプリであればとても小さく書ける。
#include <memory>
#include <stdexcept>
#include "crow_all.h"
#include <sqlite_orm/sqlite_orm.h>
struct Post {
int id;
std::string text;
std::string created;
};
int
main() {
auto storage = sqlite_orm::make_storage("bbs.db",
sqlite_orm::make_table("bbs",
sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),
sqlite_orm::make_column("text", &Post::text),
sqlite_orm::make_column("created", &Post::created)
));
storage.sync_schema();
crow::SimpleApp app;
crow::mustache::set_base(".");
CROW_ROUTE(app, "/")
([&] {
crow::mustache::context ctx;
auto posts = storage.get_all<Post>();
int n = 0;
for(auto &post : posts) {
ctx["posts"][n]["id"] = post.id;
ctx["posts"][n]["text"] = post.text;
ctx["posts"][n]["created"] = post.created;
n++;
}
return crow::mustache::load("bbs.html").render(ctx);
});
CROW_ROUTE(app, "/post").methods("POST"_method)
([&](const crow::request& req, crow::response& res) {
crow::query_string params(std::string("?") + req.body);
char* q = params.get("text");
if (q == nullptr) {
res = crow::response(400);
res.write("bad request");
res.end();
return;
}
Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now", "localtime")).front()};
storage.insert(post);
res = crow::response(302);
res.set_header("Location", "/");
res.end();
});
app.port(40081)
//.multithreaded()
.run();
}
ちょっと触ってみた感じだと SQLite3 を扱うのであれば一番便利かもしれない。