├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── makefile ├── sql.h └── test ├── CMakeLists.txt └── test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | test/build 2 | *.so 3 | test.dSYM 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: 4 | - linux 5 | 6 | env: 7 | - CONFIG=Release 8 | - CONFIG=Debug 9 | 10 | compiler: 11 | - clang 12 | 13 | script: 14 | - make all 15 | - make test 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 dongcheng.du 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sql-builder 2 | 3 | [![Build Status](https://travis-ci.org/six-ddc/sql-builder.svg?branch=master)](https://travis-ci.org/six-ddc/sql-builder) 4 | 5 | ♥️ SQL query string builder for C++11 6 | 7 | ## Examples: 8 | 9 | ``` c++ 10 | // Insert 11 | InsertModel i; 12 | i.insert("score", 100) 13 | ("name", std::string("six")) 14 | ("age", (unsigned char)20) 15 | ("address", "beijing") 16 | ("create_time", nullptr) 17 | .into("user"); 18 | assert(i.str() == 19 | "insert into user(score, name, age, address, create_time) values(100, 'six', 20, 'beijing', null)"); 20 | 21 | // Insert with named parameters 22 | InsertModel iP; 23 | Param score = ":score"; 24 | Param name = ":name"; 25 | Param age = ":age"; 26 | Param address = ":address"; 27 | Param create_time = ":create_time"; 28 | iP.insert("score", score) 29 | ("name", name) 30 | ("age", age) 31 | ("address", address) 32 | ("create_time", create_time) 33 | .into("user"); 34 | assert(iP.str() == 35 | "insert into user(score, name, age, address, create_time) values(:score, :name, :age, :address, :create_time)"); 36 | 37 | // Select 38 | SelectModel s; 39 | s.select("id as user_id", "age", "name", "address") 40 | .distinct() 41 | .from("user") 42 | .join("score") 43 | .on(column("user.id") == column("score.id") and column("score.id") > 60) 44 | .where(column("score") > 60 and (column("age") >= 20 or column("address").is_not_null())) 45 | // .where(column("score") > 60 && (column("age") >= 20 || column("address").is_not_null())) 46 | .group_by("age") 47 | .having(column("age") > 10) 48 | .order_by("age desc") 49 | .limit(10) 50 | .offset(1); 51 | std::cout << s.str() << std::endl; 52 | assert(s.str() == 53 | "select distinct id as user_id, age, name, address from user join score on (user.id = score.id) and (score.id > 60) where (score > 60) and ((age >= 20) or (address is not null)) group by age having age > 10 order by age desc limit 10 offset 1"); 54 | 55 | // Update 56 | std::vector a = {1, 2, 3}; 57 | UpdateModel u; 58 | u.update("user") 59 | .set("name", "ddc") 60 | ("age", 18) 61 | ("score", nullptr) 62 | ("address", "beijing") 63 | .where(column("id").in(a)); 64 | assert(u.str() == 65 | "update user set name = 'ddc', age = 18, score = null, address = 'beijing' where id in (1, 2, 3)"); 66 | 67 | // Update with positional parameters 68 | UpdateModel uP; 69 | Param mark = "?"; 70 | uP.update("user") 71 | .set("name", mark) 72 | ("age", mark) 73 | ("score", mark) 74 | ("address", mark) 75 | .where(column("id").in(a)); 76 | assert(uP.str() == 77 | "update user set name = ?, age = ?, score = ?, address = ? where id in (1, 2, 3)"); 78 | 79 | // Delete 80 | DeleteModel d; 81 | d._delete() 82 | .from("user") 83 | .where(column("id") == 1); 84 | assert(d.str() == 85 | "delete from user where id = 1"); 86 | ``` 87 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd test && mkdir -p build && cd build && cmake .. && make && ctest 3 | test: all 4 | cd test/build && ./sql-test 5 | clean: 6 | rm -rf test/build 7 | -------------------------------------------------------------------------------- /sql.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace sql { 7 | 8 | class column; 9 | 10 | class Param 11 | { 12 | public: 13 | Param (const std::string ¶m) : _param(param) {} 14 | Param (const char *param) : _param(param) {} 15 | 16 | public: 17 | std::string operator()() const { return param(); } 18 | inline std::string param() const { return _param; } 19 | 20 | private: 21 | const std::string _param; 22 | }; 23 | 24 | template 25 | inline std::string to_value(const T& data) { 26 | return std::to_string(data); 27 | } 28 | 29 | template 30 | inline std::string to_value(char const(&data)[N]) { 31 | std::string str("'"); 32 | str.append(data); 33 | str.append("'"); 34 | return str; 35 | } 36 | 37 | template <> 38 | inline std::string to_value(const std::string& data) { 39 | std::string str("'"); 40 | str.append(data); 41 | str.append("'"); 42 | return str; 43 | } 44 | 45 | template <> 46 | inline std::string to_value(const char* const& data) { 47 | std::string str("'"); 48 | str.append(data); 49 | str.append("'"); 50 | return str; 51 | } 52 | 53 | template <> 54 | inline std::string to_value(const Param& data) { 55 | return data(); 56 | } 57 | 58 | template <> 59 | inline std::string to_value(const column& data); 60 | 61 | /* 62 | template <> 63 | static std::string sql::to_value(const time_t& data) { 64 | char buff[128] = {0}; 65 | struct tm* ttime = localtime(&data); 66 | strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", ttime); 67 | std::string str("'"); 68 | str.append(buff); 69 | str.append("'"); 70 | return str; 71 | } 72 | */ 73 | 74 | template 75 | void join_vector(std::string& result, const std::vector& vec, const char* sep) { 76 | size_t size = vec.size(); 77 | for(size_t i = 0; i < size; ++i) { 78 | if(i < size - 1) { 79 | result.append(vec[i]); 80 | result.append(sep); 81 | } else { 82 | result.append(vec[i]); 83 | } 84 | } 85 | } 86 | 87 | class column 88 | { 89 | public: 90 | column(const std::string& column) { 91 | _cond = column; 92 | } 93 | virtual ~column() {} 94 | 95 | column& as(const std::string& s) { 96 | _cond.append(" as "); 97 | _cond.append(s); 98 | return *this; 99 | } 100 | 101 | column& is_null() { 102 | _cond.append(" is null"); 103 | return *this; 104 | } 105 | 106 | column& is_not_null() { 107 | _cond.append(" is not null"); 108 | return *this; 109 | } 110 | 111 | template 112 | column& in(const std::vector& args) { 113 | size_t size = args.size(); 114 | if(size == 1) { 115 | _cond.append(" = "); 116 | _cond.append(to_value(args[0])); 117 | } else { 118 | _cond.append(" in ("); 119 | for(size_t i = 0; i < size; ++i) { 120 | if(i < size - 1) { 121 | _cond.append(to_value(args[i])); 122 | _cond.append(", "); 123 | } else { 124 | _cond.append(to_value(args[i])); 125 | } 126 | } 127 | _cond.append(")"); 128 | } 129 | return *this; 130 | } 131 | 132 | template 133 | column& not_in(const std::vector& args) { 134 | size_t size = args.size(); 135 | if(size == 1) { 136 | _cond.append(" != "); 137 | _cond.append(to_value(args[0])); 138 | } else { 139 | _cond.append(" not in ("); 140 | for(size_t i = 0; i < size; ++i) { 141 | if(i < size - 1) { 142 | _cond.append(to_value(args[i])); 143 | _cond.append(", "); 144 | } else { 145 | _cond.append(to_value(args[i])); 146 | } 147 | } 148 | _cond.append(")"); 149 | } 150 | return *this; 151 | } 152 | 153 | column& operator &&(column& condition) { 154 | std::string str("("); 155 | str.append(_cond); 156 | str.append(") and ("); 157 | str.append(condition._cond); 158 | str.append(")"); 159 | condition._cond = str; 160 | return condition; 161 | } 162 | 163 | column& operator ||(column& condition) { 164 | std::string str("("); 165 | str.append(_cond); 166 | str.append(") or ("); 167 | str.append(condition._cond); 168 | str.append(")"); 169 | condition._cond = str; 170 | return condition; 171 | } 172 | 173 | column& operator &&(const std::string& condition) { 174 | _cond.append(" and "); 175 | _cond.append(condition); 176 | return *this; 177 | } 178 | 179 | column& operator ||(const std::string& condition) { 180 | _cond.append(" or "); 181 | _cond.append(condition); 182 | return *this; 183 | } 184 | 185 | column& operator &&(const char* condition) { 186 | _cond.append(" and "); 187 | _cond.append(condition); 188 | return *this; 189 | } 190 | 191 | column& operator ||(const char* condition) { 192 | _cond.append(" or "); 193 | _cond.append(condition); 194 | return *this; 195 | } 196 | 197 | template 198 | column& operator ==(const T& data) { 199 | _cond.append(" = "); 200 | _cond.append(to_value(data)); 201 | return *this; 202 | } 203 | 204 | template 205 | column& operator !=(const T& data) { 206 | _cond.append(" != "); 207 | _cond.append(to_value(data)); 208 | return *this; 209 | } 210 | 211 | template 212 | column& operator >=(const T& data) { 213 | _cond.append(" >= "); 214 | _cond.append(to_value(data)); 215 | return *this; 216 | } 217 | 218 | template 219 | column& operator <=(const T& data) { 220 | _cond.append(" <= "); 221 | _cond.append(to_value(data)); 222 | return *this; 223 | } 224 | 225 | template 226 | column& operator >(const T& data) { 227 | _cond.append(" > "); 228 | _cond.append(to_value(data)); 229 | return *this; 230 | } 231 | 232 | template 233 | column& operator <(const T& data) { 234 | _cond.append(" < "); 235 | _cond.append(to_value(data)); 236 | return *this; 237 | } 238 | 239 | const std::string& str() const { 240 | return _cond; 241 | } 242 | 243 | operator bool() { 244 | return true; 245 | } 246 | private: 247 | std::string _cond; 248 | }; 249 | 250 | template <> 251 | inline std::string to_value(const column& data) { 252 | return data.str(); 253 | } 254 | 255 | 256 | class SqlModel 257 | { 258 | public: 259 | SqlModel() {} 260 | virtual ~SqlModel() {} 261 | 262 | virtual const std::string& str() = 0; 263 | const std::string& last_sql() { 264 | return _sql; 265 | } 266 | private: 267 | SqlModel(const SqlModel& m) = delete; 268 | SqlModel& operator =(const SqlModel& data) = delete; 269 | protected: 270 | std::string _sql; 271 | }; 272 | 273 | class SelectModel : public SqlModel 274 | { 275 | public: 276 | SelectModel() : _distinct(false) {} 277 | virtual ~SelectModel() {} 278 | 279 | template 280 | SelectModel& select(const std::string& str, Args&&... columns) { 281 | _select_columns.push_back(str); 282 | select(columns...); 283 | return *this; 284 | } 285 | 286 | // for recursion 287 | SelectModel& select() { 288 | return *this; 289 | } 290 | 291 | SelectModel& distinct() { 292 | _distinct = true; 293 | return *this; 294 | } 295 | 296 | template 297 | SelectModel& from(const std::string& table_name, Args&&... tables) { 298 | if(_table_name.empty()) { 299 | _table_name = table_name; 300 | } else { 301 | _table_name.append(", "); 302 | _table_name.append(table_name); 303 | } 304 | from(tables...); 305 | return *this; 306 | } 307 | 308 | // for recursion 309 | SelectModel& from() { 310 | return *this; 311 | } 312 | 313 | SelectModel& join(const std::string& table_name) { 314 | _join_type = "join"; 315 | _join_table = table_name; 316 | return *this; 317 | } 318 | 319 | SelectModel& left_join(const std::string& table_name) { 320 | _join_type = "left join"; 321 | _join_table = table_name; 322 | return *this; 323 | } 324 | 325 | SelectModel& left_outer_join(const std::string& table_name) { 326 | _join_type = "left outer join"; 327 | _join_table = table_name; 328 | return *this; 329 | } 330 | 331 | SelectModel& right_join(const std::string& table_name) { 332 | _join_type = "right join"; 333 | _join_table = table_name; 334 | return *this; 335 | } 336 | 337 | SelectModel& right_outer_join(const std::string& table_name) { 338 | _join_type = "right outer join"; 339 | _join_table = table_name; 340 | return *this; 341 | } 342 | 343 | SelectModel& full_join(const std::string& table_name) { 344 | _join_type = "full join"; 345 | _join_table = table_name; 346 | return *this; 347 | } 348 | 349 | SelectModel& full_outer_join(const std::string& table_name) { 350 | _join_type = "full outer join"; 351 | _join_table = table_name; 352 | return *this; 353 | } 354 | 355 | SelectModel& on(const std::string& condition) { 356 | _join_on_condition.push_back(condition); 357 | return *this; 358 | } 359 | 360 | SelectModel& on(const column& condition) { 361 | _join_on_condition.push_back(condition.str()); 362 | return *this; 363 | } 364 | 365 | SelectModel& where(const std::string& condition) { 366 | _where_condition.push_back(condition); 367 | return *this; 368 | } 369 | 370 | SelectModel& where(const column& condition) { 371 | _where_condition.push_back(condition.str()); 372 | return *this; 373 | } 374 | 375 | template 376 | SelectModel& group_by(const std::string& str, Args&&...columns) { 377 | _groupby_columns.push_back(str); 378 | group_by(columns...); 379 | return *this; 380 | } 381 | 382 | // for recursion 383 | SelectModel& group_by() { 384 | return *this; 385 | } 386 | 387 | SelectModel& having(const std::string& condition) { 388 | _having_condition.push_back(condition); 389 | return *this; 390 | } 391 | 392 | SelectModel& having(const column& condition) { 393 | _having_condition.push_back(condition.str()); 394 | return *this; 395 | } 396 | 397 | SelectModel& order_by(const std::string& order_by) { 398 | _order_by = order_by; 399 | return *this; 400 | } 401 | 402 | template 403 | SelectModel& limit(const T& limit) { 404 | _limit = std::to_string(limit); 405 | return *this; 406 | } 407 | template 408 | SelectModel& limit(const T& offset, const T& limit) { 409 | _offset = std::to_string(offset); 410 | _limit = std::to_string(limit); 411 | return *this; 412 | } 413 | template 414 | SelectModel& offset(const T& offset) { 415 | _offset = std::to_string(offset); 416 | return *this; 417 | } 418 | 419 | virtual const std::string& str() override { 420 | _sql.clear(); 421 | _sql.append("select "); 422 | if(_distinct) { 423 | _sql.append("distinct "); 424 | } 425 | join_vector(_sql, _select_columns, ", "); 426 | _sql.append(" from "); 427 | _sql.append(_table_name); 428 | if(!_join_type.empty()) { 429 | _sql.append(" "); 430 | _sql.append(_join_type); 431 | _sql.append(" "); 432 | _sql.append(_join_table); 433 | } 434 | if(!_join_on_condition.empty()) { 435 | _sql.append(" on "); 436 | join_vector(_sql, _join_on_condition, " and "); 437 | } 438 | if(!_where_condition.empty()) { 439 | _sql.append(" where "); 440 | join_vector(_sql, _where_condition, " and "); 441 | } 442 | if(!_groupby_columns.empty()) { 443 | _sql.append(" group by "); 444 | join_vector(_sql, _groupby_columns, ", "); 445 | } 446 | if(!_having_condition.empty()) { 447 | _sql.append(" having "); 448 | join_vector(_sql, _having_condition, " and "); 449 | } 450 | if(!_order_by.empty()) { 451 | _sql.append(" order by "); 452 | _sql.append(_order_by); 453 | } 454 | if(!_limit.empty()) { 455 | _sql.append(" limit "); 456 | _sql.append(_limit); 457 | } 458 | if(!_offset.empty()) { 459 | _sql.append(" offset "); 460 | _sql.append(_offset); 461 | } 462 | return _sql; 463 | } 464 | 465 | SelectModel& reset() { 466 | _select_columns.clear(); 467 | _distinct = false; 468 | _groupby_columns.clear(); 469 | _table_name.clear(); 470 | _join_type.clear(); 471 | _join_table.clear(); 472 | _join_on_condition.clear(); 473 | _where_condition.clear(); 474 | _having_condition.clear(); 475 | _order_by.clear(); 476 | _limit.clear(); 477 | _offset.clear(); 478 | return *this; 479 | } 480 | friend inline std::ostream& operator<< (std::ostream& out, SelectModel& mod) { 481 | out< _select_columns; 487 | bool _distinct; 488 | std::vector _groupby_columns; 489 | std::string _table_name; 490 | std::string _join_type; 491 | std::string _join_table; 492 | std::vector _join_on_condition; 493 | std::vector _where_condition; 494 | std::vector _having_condition; 495 | std::string _order_by; 496 | std::string _limit; 497 | std::string _offset; 498 | }; 499 | 500 | 501 | 502 | class InsertModel : public SqlModel 503 | { 504 | public: 505 | InsertModel() {} 506 | virtual ~InsertModel() {} 507 | 508 | template 509 | InsertModel& insert(const std::string& c, const T& data) { 510 | _columns.push_back(c); 511 | _values.push_back(to_value(data)); 512 | return *this; 513 | } 514 | 515 | template 516 | InsertModel& operator()(const std::string& c, const T& data) { 517 | return insert(c, data); 518 | } 519 | 520 | InsertModel& into(const std::string& table_name) { 521 | _table_name = table_name; 522 | return *this; 523 | } 524 | 525 | InsertModel& replace(bool var) { 526 | _replace = var; 527 | return *this; 528 | } 529 | 530 | virtual const std::string& str() override { 531 | _sql.clear(); 532 | std::string v_ss; 533 | 534 | if (_replace) { 535 | _sql.append("insert or replace into "); 536 | }else { 537 | _sql.append("insert into "); 538 | } 539 | 540 | _sql.append(_table_name); 541 | _sql.append("("); 542 | v_ss.append(" values("); 543 | size_t size = _columns.size(); 544 | for(size_t i = 0; i < size; ++i) { 545 | if(i < size - 1) { 546 | _sql.append(_columns[i]); 547 | _sql.append(", "); 548 | v_ss.append(_values[i]); 549 | v_ss.append(", "); 550 | } else { 551 | _sql.append(_columns[i]); 552 | _sql.append(")"); 553 | v_ss.append(_values[i]); 554 | v_ss.append(")"); 555 | } 556 | } 557 | _sql.append(v_ss); 558 | return _sql; 559 | } 560 | 561 | InsertModel& reset() { 562 | _table_name.clear(); 563 | _columns.clear(); 564 | _values.clear(); 565 | return *this; 566 | } 567 | 568 | friend inline std::ostream& operator<< (std::ostream& out, InsertModel& mod) { 569 | out< _columns; 577 | std::vector _values; 578 | }; 579 | 580 | template <> 581 | inline InsertModel& InsertModel::insert(const std::string& c, const std::nullptr_t&) { 582 | _columns.push_back(c); 583 | _values.push_back("null"); 584 | return *this; 585 | } 586 | 587 | 588 | class UpdateModel : public SqlModel 589 | { 590 | public: 591 | UpdateModel() {} 592 | virtual ~UpdateModel() {} 593 | 594 | UpdateModel& update(const std::string& table_name) { 595 | _table_name = table_name; 596 | return *this; 597 | } 598 | 599 | template 600 | UpdateModel& set(const std::string& c, const T& data) { 601 | std::string str(c); 602 | str.append(" = "); 603 | str.append(to_value(data)); 604 | _set_columns.push_back(str); 605 | return *this; 606 | } 607 | 608 | template 609 | UpdateModel& operator()(const std::string& c, const T& data) { 610 | return set(c, data); 611 | } 612 | 613 | UpdateModel& where(const std::string& condition) { 614 | _where_condition.push_back(condition); 615 | return *this; 616 | } 617 | 618 | UpdateModel& where(const column& condition) { 619 | _where_condition.push_back(condition.str()); 620 | return *this; 621 | } 622 | 623 | virtual const std::string& str() override { 624 | _sql.clear(); 625 | _sql.append("update "); 626 | _sql.append(_table_name); 627 | _sql.append(" set "); 628 | join_vector(_sql, _set_columns, ", "); 629 | size_t size = _where_condition.size(); 630 | if(size > 0) { 631 | _sql.append(" where "); 632 | join_vector(_sql, _where_condition, " and "); 633 | } 634 | return _sql; 635 | } 636 | 637 | UpdateModel& reset() { 638 | _table_name.clear(); 639 | _set_columns.clear(); 640 | _where_condition.clear(); 641 | return *this; 642 | } 643 | friend inline std::ostream& operator<< (std::ostream& out, UpdateModel& mod) { 644 | out< _set_columns; 650 | std::string _table_name; 651 | std::vector _where_condition; 652 | }; 653 | 654 | template <> 655 | inline UpdateModel& UpdateModel::set(const std::string& c, const std::nullptr_t&) { 656 | std::string str(c); 657 | str.append(" = null"); 658 | _set_columns.push_back(str); 659 | return *this; 660 | } 661 | 662 | 663 | class DeleteModel : public SqlModel 664 | { 665 | public: 666 | DeleteModel() {} 667 | virtual ~DeleteModel() {} 668 | 669 | DeleteModel& _delete() { 670 | return *this; 671 | } 672 | 673 | template 674 | DeleteModel& from(const std::string& table_name, Args&&... tables) { 675 | if(_table_name.empty()) { 676 | _table_name = table_name; 677 | } else { 678 | _table_name.append(", "); 679 | _table_name.append(table_name); 680 | } 681 | from(tables...); 682 | return *this; 683 | } 684 | 685 | // for recursion 686 | DeleteModel& from() { 687 | return *this; 688 | } 689 | 690 | DeleteModel& where(const std::string& condition) { 691 | _where_condition.push_back(condition); 692 | return *this; 693 | } 694 | 695 | DeleteModel& where(const column& condition) { 696 | _where_condition.push_back(condition.str()); 697 | return *this; 698 | } 699 | 700 | virtual const std::string& str() override { 701 | _sql.clear(); 702 | _sql.append("delete from "); 703 | _sql.append(_table_name); 704 | size_t size = _where_condition.size(); 705 | if(size > 0) { 706 | _sql.append(" where "); 707 | join_vector(_sql, _where_condition, " and "); 708 | } 709 | return _sql; 710 | } 711 | 712 | DeleteModel& reset() { 713 | _table_name.clear(); 714 | _where_condition.clear(); 715 | return *this; 716 | } 717 | friend inline std::ostream& operator<< (std::ostream& out, DeleteModel& mod) { 718 | out< _where_condition; 725 | }; 726 | 727 | } 728 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | set(CMAKE_MACOSX_RPATH 0) 4 | 5 | project(sql-builder) 6 | 7 | set(DEBUG_FLAGS "-std=c++11 -g -O1 -Wall -Wextra -pedantic") 8 | set(RELEASE_FLAGS "-std=c++11 -O3 -Wall -Wextra -pedantic") 9 | 10 | set(CMAKE_CXX_FLAGS ${RELEASE_FLAGS}) 11 | set(CMAKE_CXX_FLAGS_DEBUG ${DEBUG_FLAGS}) 12 | set(CMAKE_CONFIGURATION_TYPES Debug Release) 13 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) 14 | 15 | include_directories(sql-test "../") 16 | 17 | set(SQL_TEST_SRC test.cpp) 18 | add_executable(sql-test ${SQL_TEST_SRC}) 19 | 20 | add_test(all "sql-test") 21 | 22 | enable_testing() 23 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "sql.h" 6 | 7 | /* 8 | 9 | create table if not exists user ( 10 | `id` int(10) unsigned not null auto_increment, 11 | `age` tinyint(8) unsigned, 12 | `score` int(10) unsigned not null default 0, 13 | `name` varchar(128) not null default '', 14 | `address` varchar(256), 15 | `create_time` datetime not null, 16 | primary key(`id`) 17 | ) 18 | 19 | */ 20 | 21 | using namespace sql; 22 | 23 | int main() 24 | { 25 | // Insert 26 | InsertModel i; 27 | i.insert("score", 100) 28 | ("name", std::string("six")) 29 | ("age", (unsigned char)20) 30 | ("address", "beijing") 31 | ("create_time", nullptr) 32 | .into("user"); 33 | assert(i.str() == 34 | "insert into user(score, name, age, address, create_time) values(100, 'six', 20, 'beijing', null)"); 35 | 36 | // Insert with named parameters 37 | InsertModel iP; 38 | Param score = ":score"; 39 | Param name = ":name"; 40 | Param age = ":age"; 41 | Param address = ":address"; 42 | Param create_time = ":create_time"; 43 | iP.insert("score", score) 44 | ("name", name) 45 | ("age", age) 46 | ("address", address) 47 | ("create_time", create_time) 48 | .into("user"); 49 | assert(iP.str() == 50 | "insert into user(score, name, age, address, create_time) values(:score, :name, :age, :address, :create_time)"); 51 | 52 | // Select 53 | SelectModel s; 54 | s.select("id as user_id", "age", "name", "address") 55 | .distinct() 56 | .from("user") 57 | .join("score") 58 | .on(column("user.id") == column("score.id") and column("score.id") > 60) 59 | .where(column("score") > 60 and (column("age") >= 20 or column("address").is_not_null())) 60 | // .where(column("score") > 60 && (column("age") >= 20 || column("address").is_not_null())) 61 | .group_by("age") 62 | .having(column("age") > 10) 63 | .order_by("age desc") 64 | .limit(10) 65 | .offset(1); 66 | assert(s.str() == 67 | "select distinct id as user_id, age, name, address from user join score on (user.id = score.id) and (score.id > 60) where (score > 60) and ((age >= 20) or (address is not null)) group by age having age > 10 order by age desc limit 10 offset 1"); 68 | 69 | // Update 70 | std::vector a = {1, 2, 3}; 71 | UpdateModel u; 72 | u.update("user") 73 | .set("name", "ddc") 74 | ("age", 18) 75 | ("score", nullptr) 76 | ("address", "beijing") 77 | .where(column("id").in(a)); 78 | assert(u.str() == 79 | "update user set name = 'ddc', age = 18, score = null, address = 'beijing' where id in (1, 2, 3)"); 80 | 81 | // Update with positional parameters 82 | UpdateModel uP; 83 | Param mark = "?"; 84 | uP.update("user") 85 | .set("name", mark) 86 | ("age", mark) 87 | ("score", mark) 88 | ("address", mark) 89 | .where(column("id").in(a)); 90 | assert(uP.str() == 91 | "update user set name = ?, age = ?, score = ?, address = ? where id in (1, 2, 3)"); 92 | 93 | // Delete 94 | DeleteModel d; 95 | d._delete() 96 | .from("user") 97 | .where(column("id") == 1); 98 | assert(d.str() == 99 | "delete from user where id = 1"); 100 | 101 | return 0; 102 | } 103 | --------------------------------------------------------------------------------