一晃眼又過去了一年,在這一年裏儘管有許多不如意的事,卻阻擋不了我前進的腳步。先用一句話來總結去年一年的狀態,那就是「無休無止的忙碌」。而這樣的忙碌狀態對我來講是不可取的,由於匱乏的忙碌只能讓頭腦處於一種混亂而機械的狀態中。在去年的時間就是工做上的煩心事困擾着我,雖有許多不錯的主意終究由於忙碌而沒有堅持,最後發現這的確是本身犯下的最大錯誤,由於後來不得不花更多時間來彌補。但願個人總結可以幫助到更多的朋友,從錯誤裏汲取經驗教訓。mysql
所得:在工做中我能涉及到許多我之前認爲十分複雜的領域,結果發現它們並無想象中的困難。從這一點裏我學習到一切看似困難的東西,只是咱們本身膽怯形成的,在沒有嘗試以前就妄下結論是多麼愚蠢啊。以前我在另外一個城市裏就是由於不相信本身,而喪失了許多的機會,若是有了這些機會我事業上恐怕不會現在天這般不順。因此我但願全部在困難面前畏首畏尾的朋友,大家大膽一點放開大家的懷抱,去擁抱那即將靠近的夢想,雖然沒法保證結果多是一次慘痛的失敗。但是你不趁着你還敢夢想的年紀,那麼後面的生活你就只能活在遺憾當中了。git
所失:忙碌讓個人神經麻木,甚至身體也有點力不從心,這就形成我在本身理想面前放慢了腳步。在此我也但願各位朋友要重視本身的健康,就算工做再怎麼幸苦也不能由於拼命而輕視了它,別將生活的壓力想象的太大。畢竟只有一個無缺的人,才能體會到美好的生活,而工做只不過是爲了生活而服務的。github
雖然本身的確由於時間和身體的緣由,在這個框架上花費的時間少了許多,但是我卻沒有中止我對它的期許,那即是作到真正的簡單易用。爲了作到這個我從2015年開始到如今幾乎花了三年時間修改了兩次結構,而PF框架如今的版本已經到了2.1,其基本的功能和性能獲得了必定的保證。其中過程的艱辛,恐怕沒有幾我的能體會到。sql
PF改動:plain server(2014)-> plain framework 1(2015-2016) -> plain framework 2(2017) -> plain framework new(2018)數據庫
我只有一個簡單的年份和版本變化來表示PF框架的蛻變過程,實際上是一場很是不容易的變化。一開始這個還不能稱之框架,那個時候我只是想簡單的應付工做上的事情,爲服務器打造一個穩定的底層庫,即2014年的plain server。接着我發現只爭對服務器來講根本沒法知足個人要求,因而我從新修改告終構讓它可以支持幾乎全部的常見應有。接着說道如今比較穩定的版本PF2,它的改動最大的就是從語法上直接用到了C++11,使得框架自己可以支持更多新特性。然而PF2仍是不能知足我,我將要進行各大一步的調整,在PF2的基礎上我修改了框架的目錄結構,讓它看起來更加清晰易懂。服務器
PFnew的新特性:快速安裝(框架、插件)、單元測試(框架、應用)、靈活封裝(接口)網絡
對於如今的PFnew的快速安裝目前只支持UNIX/LINUX的平臺,固然後續會想辦法支持WINDOWS系統。而單元測試則使用了gtest,目的是讓一些問題更能及早的發現,這一點我也會徵求更多的意見,由於我以前雖然接觸過這個框架,只是一直沒有使用,而對這個測試框架來講也不知道它的優缺點。至於靈活封裝就是移除了核心接口中的許多依賴,我將這部分東西移到了插件中,如今的插件中就有如腳本插件(lua)、數據庫插件(odbc)、網絡協議插件(google protobuf),而這些插件能夠根據應用的須要又框架自己提供接口來加載使用。並且若是有人用心的話,可能會在框架裏發現一個有趣的模塊,那就是數據庫的語法封裝部分(DB QUERY BUILDER),會支持大部分的數據庫語法,這樣使得咱們想要隨意切換不一樣數據庫提供了良好的支持,固然這部分仍舊是嘗試階段。並且關於這個語法封裝器,我參考了Laravel(PHP框架)的代碼,有興趣的同仁能夠去了解一下。app
在這裏貼一段代碼來看看咱們PFnew的數據庫語法的支持以及單元測試示例:框架
#include "gtest/gtest.h" #include "pf/engine/kernel.h" #include "pf/db/query/grammars/grammar.h" #include "pf/db/query/grammars/mysql_grammar.h" #include "pf/db/connection.h" #include "pf/db/query/builder.h" #include "pf/support/helpers.h" enum { kDBTypeODBC = 1, }; using namespace pf_db::query; using namespace pf_basic::type; class DBQueryBuilder : public testing::Test { public: static void SetUpTestCase() { GLOBALS["log.print"] = false; //First forbid the log print. GLOBALS["default.db.open"] = true; GLOBALS["default.db.type"] = kDBTypeODBC; GLOBALS["default.db.name"] = "pf_test"; GLOBALS["default.db.user"] = "root"; GLOBALS["default.db.password"] = "mysql"; engine_.add_libraryload("pf_plugin_odbc", {kDBTypeODBC}); engine_.init(); auto connection = new pf_db::Connection(engine_.get_db()); unique_move(pf_db::Connection, connection, connection_); auto builder = new Builder(connection_.get(), nullptr); unique_move(Builder, builder, builder_); auto mysql_grammar = new grammars::MysqlGrammar(); unique_move(grammars::Grammar, mysql_grammar, mysql_grammar_); auto mysql_builder = new Builder(connection_.get(), mysql_grammar_.get()); unique_move(Builder, mysql_builder, mysql_builder_); } static void TearDownTestCase() { //std::cout << "TearDownTestCase" << std::endl; } public: virtual void SetUp() { builder_->clear(); mysql_builder_->clear(); } virtual void TearDown() { } protected: static pf_engine::Kernel engine_; static std::unique_ptr<pf_db::Connection> connection_; static std::unique_ptr<grammars::Grammar> mysql_grammar_; static std::unique_ptr<Builder> builder_; static std::unique_ptr<Builder> mysql_builder_; }; pf_engine::Kernel DBQueryBuilder::engine_; std::unique_ptr<pf_db::Connection> DBQueryBuilder::connection_{nullptr}; std::unique_ptr<Builder> DBQueryBuilder::builder_{nullptr}; std::unique_ptr<Builder> DBQueryBuilder::mysql_builder_{nullptr}; std::unique_ptr<grammars::Grammar> DBQueryBuilder::mysql_grammar_{nullptr}; TEST_F(DBQueryBuilder, construct) { Builder object(nullptr, nullptr); pf_db::Connection connection(engine_.get_db()); Builder builder_test1(&connection, nullptr); grammars::Grammar grammar; Builder builder_test2(&connection, &grammar); } TEST_F(DBQueryBuilder, testBasicSelect) { builder_->select({"*"}).from("users"); ASSERT_STREQ("select * from \"users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicSelectWithGetColumns) { builder_->from("users").get(); ASSERT_TRUE(builder_->columns_.empty()); ASSERT_STREQ("select * from \"users\"", builder_->to_sql().c_str()); ASSERT_TRUE(builder_->columns_.empty()); } TEST_F(DBQueryBuilder, testBasicSelectUseWritePdo) { } TEST_F(DBQueryBuilder, testBasicTableWrappingProtectsQuotationMarks) { builder_->select({"*"}).from("some\"table"); ASSERT_STREQ("select * from \"some\"\"table\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testAliasWrappingAsWholeConstant) { builder_->select({"x.y as foo.bar"}).from("baz"); ASSERT_STREQ("select \"x\".\"y\" as \"foo.bar\" from \"baz\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testAliasWrappingWithSpacesInDatabaseName) { builder_->select({"w x.y.z as foo.bar"}).from("baz"); ASSERT_STREQ("select \"w x\".\"y\".\"z\" as \"foo.bar\" from \"baz\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testAddingSelects) { builder_->select({"foo"}). add_select({"bar"}).add_select({"baz", "boom"}).from("users"); ASSERT_STREQ("select \"foo\", \"bar\", \"baz\", \"boom\" from \"users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicSelectWithPrefix) { builder_->get_grammar()->set_table_prefix("prefix_"); builder_->select({"*"}).from("users"); ASSERT_STREQ("select * from \"prefix_users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicSelectDistinct) { builder_->distinct().select({"foo", "bar"}).from("users"); ASSERT_STREQ("select distinct \"foo\", \"bar\" from \"users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicAlias) { builder_->select({"foo as bar"}).from("users"); ASSERT_STREQ("select \"foo\" as \"bar\" from \"users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testAliasWithPrefix) { builder_->get_grammar()->set_table_prefix("prefix_"); builder_->select({"*"}).from("users as people"); ASSERT_STREQ("select * from \"prefix_users\" as \"prefix_people\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testJoinAliasesWithPrefix) { builder_->get_grammar()->set_table_prefix("prefix_"); builder_->select({"*"}).from("services").join( "translations AS t", "t.item_id", "=", "services.id"); ASSERT_STREQ( "select * from \"prefix_services\" inner join \"prefix_translations\" \ as \"prefix_t\" on \"prefix_t\".\"item_id\" = \"prefix_services\".\"id\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicTableWrapping) { builder_->select({"*"}).from("public.users"); ASSERT_STREQ("select * from \"public\".\"users\"", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testWhenCallback) { auto callback = [](Builder *query, const variable_t &condition) { ASSERT_TRUE(condition.get<bool>()); query->where("id", "=", 1); }; builder_->select({"*"}).from("users").when(true, callback).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); builder_->clear(); builder_->select({"*"}).from("users").when(false, callback).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"email\" = ?", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testWhenCallbackWithReturn) { } void assertEquals( const variable_array_t &a, const variable_array_t &b, int32_t line = -1) { if (line != -1) std::cout << "assertEquals: " << line << std::endl; ASSERT_TRUE(a.size() == b.size()); for (size_t i = 0; i < a.size(); ++i) ASSERT_STREQ(a[i].data.c_str(), b[i].data.c_str()); } TEST_F(DBQueryBuilder, testWhenCallbackWithDefault) { auto callback = [](Builder *query, const variable_t &condition) { ASSERT_STREQ(condition.c_str(), "truthy"); query->where("id", "=", 1); }; auto def = [](Builder *query, const variable_t &condition) { ASSERT_TRUE(condition == 0); query->where("id", "=", 2); }; builder_->select({"*"}). from("users").when("truthy", callback, def).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); assertEquals({1, "foo"}, builder_->get_bindings(), __LINE__); builder_->clear(); builder_->select({"*"}). from("users").when(0, callback, def).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); assertEquals({2, "foo"}, builder_->get_bindings(), __LINE__); } TEST_F(DBQueryBuilder, testUnlessCallback) { auto callback = [](Builder *query, const variable_t &condition) { ASSERT_FALSE(condition.get<bool>()); query->where("id", "=", 1); }; builder_->select({"*"}). from("users").unless(false, callback).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); builder_->clear(); builder_->select({"*"}). from("users").unless(true, callback).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"email\" = ?", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testUnlessCallbackWithReturn) { } TEST_F(DBQueryBuilder, testUnlessCallbackWithDefault) { auto callback = [](Builder *query, const variable_t &condition) { ASSERT_TRUE(condition == 0); query->where("id", "=", 1); }; auto def = [](Builder *query, const variable_t &condition) { ASSERT_STREQ(condition.c_str(), "truthy"); query->where("id", "=", 2); }; builder_->select({"*"}). from("users").unless(0, callback, def).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); assertEquals({1, "foo"}, builder_->get_bindings(), __LINE__); builder_->clear(); builder_->select({"*"}). from("users").unless("truthy", callback, def).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); assertEquals({2, "foo"}, builder_->get_bindings(), __LINE__); } TEST_F(DBQueryBuilder, testTapCallback) { auto callback = [](Builder *query) { query->where("id", "=", 1); }; builder_->select({"*"}).from("users").tap(callback).where("email", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? and \"email\" = ?", builder_->to_sql().c_str()); } TEST_F(DBQueryBuilder, testBasicWheres) { builder_->select({"*"}).from("users").where("id", "=", 1); ASSERT_STREQ("select * from \"users\" where \"id\" = ?", builder_->to_sql().c_str()); assertEquals({1}, builder_->get_bindings()); } TEST_F(DBQueryBuilder, testMySqlWrappingProtectsQuotationMarks) { /** builder_->select({"*"}).from("some`table"); ASSERT_STREQ("select * from `some``table`", builder_->to_sql().c_str()); **/ } TEST_F(DBQueryBuilder, testDateBasedWheresAcceptsTwoArguments) { auto builder = mysql_builder_.get(); builder->select({"*"}).from("users").where_date("created_at", "1"); ASSERT_STREQ("select * from `users` where date(`created_at`) = ?", builder->to_sql().c_str()); builder->clear(); builder->select({"*"}).from("users").where_day("created_at", "1"); ASSERT_STREQ("select * from `users` where day(`created_at`) = ?", builder->to_sql().c_str()); builder->clear(); builder->select({"*"}).from("users").where_month("created_at", "1"); ASSERT_STREQ("select * from `users` where month(`created_at`) = ?", builder->to_sql().c_str()); builder->clear(); builder->select({"*"}).from("users").where_year("created_at", "1"); ASSERT_STREQ("select * from `users` where year(`created_at`) = ?", builder->to_sql().c_str()); } TEST_F(DBQueryBuilder, testWhereDayMySql) { auto builder = mysql_builder_.get(); builder->select({"*"}).from("users").where_day("created_at", "=", 1); ASSERT_STREQ("select * from `users` where day(`created_at`) = ?", builder->to_sql().c_str()); assertEquals({1}, builder->get_bindings()); } TEST_F(DBQueryBuilder, testWhereMonthMySql) { auto builder = mysql_builder_.get(); builder->select({"*"}).from("users").where_month("created_at", "=", 5); ASSERT_STREQ("select * from `users` where month(`created_at`) = ?", builder->to_sql().c_str()); assertEquals({5}, builder->get_bindings()); } TEST_F(DBQueryBuilder, testWhereYearMySql) { auto builder = mysql_builder_.get(); builder->select({"*"}).from("users").where_year("created_at", "=", 2018); ASSERT_STREQ("select * from `users` where year(`created_at`) = ?", builder->to_sql().c_str()); assertEquals({2018}, builder->get_bindings()); } TEST_F(DBQueryBuilder, testWhereTimeMySql) { auto builder = mysql_builder_.get(); builder->select({"*"}).from("users").where_time("created_at", "=", "22:00"); ASSERT_STREQ("select * from `users` where time(`created_at`) = ?", builder->to_sql().c_str()); assertEquals({"22:00"}, builder->get_bindings()); } TEST_F(DBQueryBuilder, testWhereDatePostgres) { } TEST_F(DBQueryBuilder, testWhereDayPostgres) { } TEST_F(DBQueryBuilder, testWhereMonthPostgres) { } TEST_F(DBQueryBuilder, testWhereYearPostgres) { } TEST_F(DBQueryBuilder, testWhereDaySqlite) { } TEST_F(DBQueryBuilder, testWhereMonthSqlite) { } TEST_F(DBQueryBuilder, testWhereYearSqlite) { } TEST_F(DBQueryBuilder, testWhereDaySqlServer) { } TEST_F(DBQueryBuilder, testWhereMonthSqlServer) { } TEST_F(DBQueryBuilder, testWhereYearSqlServer) { } TEST_F(DBQueryBuilder, testWhereBetweens) { builder_->select({"*"}).from("users").where_between("id", {1, 2}); ASSERT_STREQ("select * from \"users\" where \"id\" between ? and ?", builder_->to_sql().c_str()); assertEquals({1, 2}, builder_->get_bindings()); builder_->clear(); builder_->select({"*"}).from("users").where_notbetween("id", {1, 2}); ASSERT_STREQ("select * from \"users\" where \"id\" not between ? and ?", builder_->to_sql().c_str()); assertEquals({1, 2}, builder_->get_bindings()); } TEST_F(DBQueryBuilder, testBasicOrWheres) { builder_->select({"*"}). from("users").where("id", "=", 1).or_where("email", "=", "foo"); ASSERT_STREQ("select * from \"users\" where \"id\" = ? or \"email\" = ?", builder_->to_sql().c_str()); assertEquals({1, "foo"}, builder_->get_bindings()); } TEST_F(DBQueryBuilder, testRawWheres) { builder_->select({"*"}). from("users").where_raw("id = ? or email = ?", {1, "foo"}); ASSERT_STREQ("select * from \"users\" where id = ? or email = ?", builder_->to_sql().c_str()); assertEquals({1, "foo"}, builder_->get_bindings()); } TEST_F(DBQueryBuilder, testRawOrWheres) { builder_->select({"*"}). from("users").where("id", "=", 1).or_where_raw("email = ?", {"foo"}); ASSERT_STREQ("select * from \"users\" where \"id\" = ? or email = ?", builder_->to_sql().c_str()); assertEquals({1, "foo"}, builder_->get_bindings()); }