From c3e68c7b4c0815439e5243f6d9d7ffb37b42dc1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=96=E5=8E=9A=E6=A3=A0?= Date: Mon, 5 May 2025 10:24:53 +0800 Subject: [PATCH 1/2] feat: add create_table DSL, struct mapping, and extended type support - Introduced DECLARE_SQLITE_FIELDS macro for declarative mapping of C++ structs to SQLite tables. - Enables ORM-style interaction by registering fields and their corresponding column names. - Simplifies querying and data binding using typed structs like UserInfo. - Implemented fluent db.create_table("table") DSL for defining SQLite schemas in a readable, chainable syntax. - Supports field types (INTEGER, TEXT, BLOB, REAL), constraints (NOT NULL, PRIMARY KEY, AUTOINCREMENT), default values, and string size limits. - Used to define tables such as "user" and "people" with full schema control. - Extended support for standard library numeric and boolean types: - Added explicit specializations for bool, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t. - Improved value extraction and binding from SQLite statements. - Enhanced type safety and range checks when enabled via SQLITELIB_ENABLE_TYPE_CHECKING. - Comprehensive test coverage added: - Insertion and querying of structured data. - Field binding and result iteration. - Exception handling for invalid operations and malformed queries. This change significantly improves the usability, expressiveness, and robustness of the SQLite ORM layer. --- sqlitelib.h | 706 ++++++++++++++++++++++++++++++++++++++++++++++++++- test/test.cc | 80 +++++- 2 files changed, 778 insertions(+), 8 deletions(-) diff --git a/sqlitelib.h b/sqlitelib.h index 98d825e..a115a75 100644 --- a/sqlitelib.h +++ b/sqlitelib.h @@ -12,12 +12,74 @@ #include #include +#include #include #include #include #include #include +#define SQLITELIB_ENABLE_TYPE_CHECKING + + +// STRUCT REGISTER MACRO + +// clang-format: off +#define DECLARE_SQLITE_FIELDS(structName, ...) \ +static void registerFields(SqliteStruct& reg) { \ +reg SQLITELIB_FOR_EACH_RMAP_IMPL_(structName, __VA_ARGS__); \ +} + +#define SQLITELIB_MAP_FIELD_(structName, field) .map(&structName::field, #field) + +#define SQLITELIB_GET_TH_ARG_( _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + NAME, ...) NAME + +#define SQLITELIB_FOR_EACH_RMAP_IMPL_(structName, ...) \ + SQLITELIB_GET_TH_ARG_(__VA_ARGS__\ + , SQLITELIB_FOR_EACH_RMAP30_, SQLITELIB_FOR_EACH_RMAP29_, SQLITELIB_FOR_EACH_RMAP28_, SQLITELIB_FOR_EACH_RMAP27_, SQLITELIB_FOR_EACH_RMAP26_ \ + , SQLITELIB_FOR_EACH_RMAP25_, SQLITELIB_FOR_EACH_RMAP24_, SQLITELIB_FOR_EACH_RMAP23_, SQLITELIB_FOR_EACH_RMAP22_, SQLITELIB_FOR_EACH_RMAP21_ \ + , SQLITELIB_FOR_EACH_RMAP20_, SQLITELIB_FOR_EACH_RMAP19_, SQLITELIB_FOR_EACH_RMAP18_, SQLITELIB_FOR_EACH_RMAP17_, SQLITELIB_FOR_EACH_RMAP16_ \ + , SQLITELIB_FOR_EACH_RMAP15_, SQLITELIB_FOR_EACH_RMAP14_, SQLITELIB_FOR_EACH_RMAP13_, SQLITELIB_FOR_EACH_RMAP12_, SQLITELIB_FOR_EACH_RMAP11_ \ + , SQLITELIB_FOR_EACH_RMAP10_, SQLITELIB_FOR_EACH_RMAP09_, SQLITELIB_FOR_EACH_RMAP08_, SQLITELIB_FOR_EACH_RMAP07_, SQLITELIB_FOR_EACH_RMAP06_ \ + , SQLITELIB_FOR_EACH_RMAP05_, SQLITELIB_FOR_EACH_RMAP04_, SQLITELIB_FOR_EACH_RMAP03_, SQLITELIB_FOR_EACH_RMAP02_, SQLITELIB_FOR_EACH_RMAP01_ \ + )(structName, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP01_(structName, field) SQLITELIB_MAP_FIELD_(structName, field) +#define SQLITELIB_FOR_EACH_RMAP02_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP01_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP03_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP02_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP04_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP03_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP05_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP04_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP06_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP05_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP07_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP06_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP08_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP07_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP09_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP08_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP10_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP09_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP11_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP10_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP12_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP11_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP13_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP12_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP14_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP13_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP15_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP14_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP16_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP15_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP17_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP16_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP18_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP17_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP19_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP18_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP20_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP19_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP21_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP20_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP22_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP21_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP23_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP22_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP24_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP23_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP25_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP24_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP26_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP25_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP27_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP26_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP28_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP27_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP29_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP28_(structName, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP30_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP29_(structName, __VA_ARGS__) + +// clang-format: on + namespace sqlitelib { namespace { @@ -29,23 +91,170 @@ inline void verify(int rc, int expected = SQLITE_OK) { throw std::exception(); } } +// sqlite3_value_double sqlite3_value + + template R get_column_value(sqlite3_value* val); + template <> int get_column_value(sqlite3_value* val) { return sqlite3_value_int(val); } + template <> int64_t get_column_value(sqlite3_value* val) { return sqlite3_value_int64(val); } + template <> uint64_t get_column_value(sqlite3_value* val) { return static_cast(sqlite3_value_int64(val)); } + template <> double get_column_value(sqlite3_value* val) { return sqlite3_value_double(val); } + template <> float get_column_value(sqlite3_value* val) { return static_cast(sqlite3_value_double(val)); } + template <> bool get_column_value(sqlite3_value* val) { return sqlite3_value_int(val) == 1; } + template <> std::string get_column_value(sqlite3_value* val) { + auto result = std::string(sqlite3_value_bytes(val), 0); + memcpy(&result[0], sqlite3_value_text(val), result.size()); + return result; + } + template <> + std::string get_column_value(sqlite3_value* val) { + auto result = std::string(sqlite3_value_bytes(val), 0); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template <> + std::string get_column_value(sqlite3_value* val) { + auto result = std::string(sqlite3_value_bytes(val), 0); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template <> + std::vector get_column_value>(sqlite3_value* val) { + auto result = std::vector(sqlite3_value_bytes(val)); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template <> + std::string get_column_value(sqlite3_value* val) { + auto result = std::string(sqlite3_value_bytes(val), 0); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template <> + std::string get_column_value(sqlite3_value* val) { + auto result = std::string(sqlite3_value_bytes(val), 0); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template <> + std::vector get_column_value>(sqlite3_value* val) { + auto result = std::vector(sqlite3_value_bytes(val)); + memcpy(&result[0], sqlite3_value_blob(val), result.size()); + return result; + } + template T get_column_value(sqlite3_stmt* stmt, int col) {} +template <> +bool get_column_value(sqlite3_stmt* stmt, int col) { +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + auto type = sqlite3_column_type(stmt, col); + switch (type) { + case SQLITE_INTEGER: return sqlite3_column_int(stmt, col) != 0; + case SQLITE_TEXT: { + std::string text = std::string(sqlite3_column_bytes(stmt, col), 0); + memcpy(&text[0], sqlite3_column_text(stmt, col), text.size()); + std::transform(text.begin(), text.end(), text.begin(), [](unsigned char c) { return std::tolower(c); }); + // Note: This is not very efficient support, you can do better + if (text == "1" || text == "t" || text == "true") return true; + if (text.empty()|| text == "0" || text == "f" || text == "false") return false; + throw std::runtime_error("Cannot convert column to bool('" + text + "')"); + } + case SQLITE_NULL: + return false; + default: + throw std::runtime_error("Cannot convert column to bool"); + } +#else + return sqlite3_column_int(stmt, col) != 0; +#endif + +} + + template <> + int16_t get_column_value(sqlite3_stmt* stmt, int col) { + auto val = sqlite3_column_int(stmt, col); +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + if (val > std::numeric_limits::max() || val < 0) { + throw std::runtime_error("Value is too large for short"); + } +#endif + return static_cast(val); + } + + template <> + uint16_t get_column_value(sqlite3_stmt* stmt, int col) { + auto val = sqlite3_column_int(stmt, col); +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + if (val > std::numeric_limits::max() || val < 0) { + throw std::runtime_error("Value is too large for ushort"); + } +#endif + return static_cast(val); + } + template <> int get_column_value(sqlite3_stmt* stmt, int col) { return sqlite3_column_int(stmt, col); } + template <> + uint32_t get_column_value(sqlite3_stmt* stmt, int col) { + auto val = sqlite3_column_int64(stmt, col); +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + if (val > std::numeric_limits::max() || val < 0) { + throw std::runtime_error("Value is too large for uint"); + } +#endif + return static_cast(val); + } + +template <> +long get_column_value(sqlite3_stmt* stmt, int col) { + auto val = sqlite3_column_int64(stmt, col); +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + if (val > std::numeric_limits::max() || val < std::numeric_limits::min()) { + throw std::runtime_error("Value is too large for long"); + } +#endif + return static_cast(val); +} + + template <> + unsigned long get_column_value(sqlite3_stmt* stmt, int col) { + auto val = sqlite3_column_int64(stmt, col); +#ifdef SQLITELIB_ENABLE_TYPE_CHECKING + if (val > std::numeric_limits::max() || val < 0) { + throw std::runtime_error("Value is too large for ulong"); + } +#endif + return static_cast(val); + } + +template <> +int64_t get_column_value(sqlite3_stmt* stmt, int col) { + return sqlite3_column_int64(stmt, col); +} + +template <> +uint64_t get_column_value(sqlite3_stmt* stmt, int col) { + return static_cast(sqlite3_column_int64(stmt, col)); +} + template <> double get_column_value(sqlite3_stmt* stmt, int col) { return sqlite3_column_double(stmt, col); } +template <> +float get_column_value(sqlite3_stmt* stmt, int col) { + return static_cast(sqlite3_column_double(stmt, col)); +} + template <> std::string get_column_value(sqlite3_stmt* stmt, int col) { - auto val = std::string(sqlite3_column_bytes(stmt, col), 0); + std::string val = std::string(sqlite3_column_bytes(stmt, col), 0); memcpy(&val[0], sqlite3_column_text(stmt, col), val.size()); return val; } @@ -79,16 +288,68 @@ struct ColumnValues<1, T> { template void bind_value(sqlite3_stmt* stmt, int col, Arg val) {} +template <> +void bind_value(sqlite3_stmt* stmt, int col, bool val) { + auto type = sqlite3_column_type(stmt, col); + switch (type) { + case SQLITE_NULL : verify(sqlite3_bind_int(stmt, col, val ? 1 : 0)); break; + case SQLITE_INTEGER: verify(sqlite3_bind_int(stmt, col, val ? 1 : 0)); break; + case SQLITE_TEXT : { + std::string text = val ? "true" : "false"; + verify(sqlite3_bind_text(stmt, col, text.data(), static_cast(text.size()), SQLITE_TRANSIENT)); + } break; + default: + throw std::runtime_error("bind value failed"); + } +} + +template <> +void bind_value(sqlite3_stmt* stmt, int col, int16_t val) { + verify(sqlite3_bind_int(stmt, col, val)); +} +template <> +void bind_value(sqlite3_stmt* stmt, int col, uint16_t val) { + verify(sqlite3_bind_int(stmt, col, val)); +} template <> void bind_value(sqlite3_stmt* stmt, int col, int val) { verify(sqlite3_bind_int(stmt, col, val)); } +template <> +void bind_value(sqlite3_stmt* stmt, int col, uint32_t val) { + verify(sqlite3_bind_int64(stmt, col, val)); +} + +template <> +void bind_value(sqlite3_stmt* stmt, int col, long val) { + verify(sqlite3_bind_int64(stmt, col, val)); +} +template <> +void bind_value(sqlite3_stmt* stmt, int col, unsigned long val) { + verify(sqlite3_bind_int64(stmt, col, val)); +} + +template <> +void bind_value(sqlite3_stmt* stmt, int col, int64_t val) { + verify(sqlite3_bind_int64(stmt, col, static_cast(val))); +} + +template <> +void bind_value(sqlite3_stmt* stmt, int col, uint64_t val) { + verify(sqlite3_bind_int64(stmt, col, static_cast(val))); +} + template <> void bind_value(sqlite3_stmt* stmt, int col, double val) { verify(sqlite3_bind_double(stmt, col, val)); } +template <> +void bind_value(sqlite3_stmt* stmt, int col, float val) { + verify(sqlite3_bind_double(stmt, col, static_cast(val))); +} + template <> void bind_value(sqlite3_stmt* stmt, int col, std::string val) { verify(sqlite3_bind_text(stmt, col, val.data(), static_cast(val.size()), @@ -168,6 +429,8 @@ class Iterator { bool operator!=(const Iterator& rhs) { return !operator==(rhs); } + sqlite3_stmt* statement() { return stmt_; } + int id() { return id_; } private: sqlite3_stmt* stmt_; int id_; @@ -327,10 +590,451 @@ class Sqlite { return prepare(query).execute_cursor(args...); } + bool isTableExists(const char* tableName) const { + const char* sql = "SELECT COUNT(name) FROM sqlite_master WHERE type='table' AND name=?;"; + const int val = this->prepare(sql).execute_value(tableName); + return val > 0; + } + void dropTable(const char* tableName) { + const std::string sql = "DROP TABLE IF EXISTS " + std::string(tableName) + ";"; + execute(sql.c_str()); + } + void dropTableData(const char* tableName, bool resetAutoIncrement = true) { + if (!isTableExists(tableName)) return; + std::string sql = "DELETE FROM " + std::string(tableName) + ";"; + execute(sql.c_str()); + if (resetAutoIncrement) { + sql = "DELETE FROM sqlite_sequence WHERE name='" + std::string(tableName) + "';"; + execute(sql.c_str()); + } + } + + enum IdentifierType { FieldName, TableName, FieldValue }; + + static std::string escapeIdentifier(const std::string &identifier, IdentifierType type = FieldValue) { + if (identifier.empty()) { + return identifier; + } + + std::string escaped = identifier; + + switch (type) { + case FieldName: + case TableName: { + // Escape double quotes (" → "") + size_t pos = 0; + while ((pos = escaped.find('"', pos)) != std::string::npos) { + escaped.replace(pos, 1, "\"\""); + pos += 2; + } + + // Handle dots (table.column → "table"."column") + pos = 0; + while ((pos = escaped.find('.', pos)) != std::string::npos) { + escaped.replace(pos, 1, "\".\""); + pos += 3; + } + + // Wrap in double quotes (if not already) + if (escaped.front() != '"') escaped.insert(0, 1, '"'); + if (escaped.back() != '"') escaped.append(1, '"'); + } break; + + case FieldValue: { + // Escape single quotes (' → '') + size_t pos = 0; + while ((pos = escaped.find('\'', pos)) != std::string::npos) { + escaped.replace(pos, 1, "''"); + pos += 2; + } + + // Wrap in single quotes (if not already) + if (escaped.front() != '\'') escaped.insert(0, 1, '\''); + if (escaped.back() != '\'') escaped.append(1, '\''); + } break; + } + + return escaped; + } + + template class PreparedStatement; + + template + PreparedStatement query(const char* sql) { + return PreparedStatement(db_, sql); + } + + template class ColumnBuilder; + class TableBuilder; + + TableBuilder create_table(const std::string& name); + private: + sqlite3* db_; + template friend class PreparedStatement; }; +// =================== Table Builder =================== +class Sqlite::TableBuilder { +public: + explicit TableBuilder(std::string tableName, Sqlite &db) + : tableName_(std::move(tableName)) + , db_(db) + {} + + TableBuilder* operator->() { return this; } + + TableBuilder& if_not_exists() { + is_if_not_exists_ = "IF NOT EXISTS"; + return *this; + } + + template + ColumnBuilder column(const std::string& name) { + return ColumnBuilder(this, name); + } + + void execute() { + auto sql = build_sql(); + // printf("Executing: %s\n", sql.c_str()); + // fflush(stdout); + db_.prepare(sql.c_str()).execute(); + } + +private: + std::string build_sql() const { + std::ostringstream oss; + oss << "CREATE TABLE "; + if (!is_if_not_exists_.empty()) oss << is_if_not_exists_ << " "; + oss << tableName_ << " (\n"; + + for (size_t i = 0; i < columns_.size(); ++i) { + const auto& col = columns_[i]; + oss << " " << col.name << " "; + switch (col.type) { + case ColumnType::TEXT : oss << "TEXT" ; break; + case ColumnType::INTEGER: oss << "INTEGER" ; break; + case ColumnType::Bool : oss << "INTEGER(1)"; break; + case ColumnType::REAL : oss << "REAL" ; break; + case ColumnType::BLOB : oss << "BLOB" ; break; + } + + if (col.type != ColumnType::Bool && col.options.size > 0) { + oss << "(" << col.options.size << ")"; + } + + if (col.options.is_not_null) { + oss << " NOT NULL"; + } + + if (!col.options.default_value.empty() && col.options.default_value != "AUTOINCREMENT") { + oss << " DEFAULT " << col.options.default_value; + } + + if (col.options.is_primary_key) { + oss << " PRIMARY KEY"; + if (col.options.default_value == "AUTOINCREMENT") { + oss << " AUTOINCREMENT"; + } + } + + if (i != columns_.size() - 1) { + oss << ","; + } + oss << "\n"; + } + + oss << ");\n"; + return oss.str(); + } + +private: + template friend class Sqlite::ColumnBuilder; + // friend class Sqlite::ColumnBuilder; + + // --- CreateTableStatement DSL for SQLite table creation --- + enum class ColumnType { + TEXT, + INTEGER, + Bool, + REAL, + BLOB + }; + struct ColumnOptions { + bool is_primary_key = false; + bool is_not_null = false; + std::string default_value; + int size = 0; + }; + + struct Column { + std::string name; + ColumnType type; + ColumnOptions options; + }; + + + std::string tableName_; + std::string is_if_not_exists_; + std::vector columns_; + + Sqlite& db_; +}; + +// =================== Column Builder =================== +template +class Sqlite::ColumnBuilder { +public: + ColumnBuilder(TableBuilder* parent, const std::string& name) + : parent_(parent) + { + using ColumnType = Sqlite::TableBuilder::ColumnType; + if constexpr (std::is_same_v) { + col_.type = ColumnType::TEXT; + } else if constexpr (std::is_same_v) { + col_.type = ColumnType::BLOB; + } else if constexpr (std::is_same_v) { + col_.type = ColumnType::Bool; + col_.options.size = 1; + } else if constexpr (std::is_floating_point_v) { + col_.type = ColumnType::REAL; + } else if constexpr (std::is_integral_v) { + col_.type = ColumnType::INTEGER; + } else if constexpr (std::is_same_v>) { + col_.type = ColumnType::BLOB; + } else { + static_assert(sizeof(T) == -1, "Unsupported column type"); + } + + col_.name = name ; + col_.options.is_primary_key = false; + col_.options.is_not_null = false; + } + + ColumnBuilder& not_null() { + col_.options.is_not_null = true; + return *this; + } + + ColumnBuilder& default_value(const T &value) { + std::ostringstream oss; + + if constexpr (std::is_same_v) { + oss << escapeIdentifier(value); + } else if constexpr (std::is_same_v) { + oss << (value ? 1 : 0); + } else if constexpr (std::is_integral::value) { + oss << value; + } + + col_.options.default_value = oss.str(); + return *this; + } + ColumnBuilder& primary_key() { + col_.options.is_primary_key = true; + return *this; + } + ColumnBuilder& autoincrement() { + using ColumnType = Sqlite::TableBuilder::ColumnType; + if (col_.type != ColumnType::INTEGER) { + throw std::runtime_error("AUTOINCREMENT only allowed on INTEGER columns"); + } + col_.options.default_value = "AUTOINCREMENT"; + return *this; + } + ColumnBuilder& size(int value) { + static_assert(std::is_same_v, "Only string columns can have a size."); + col_.options.size = value; + return *this; + } + + TableBuilder* operator->() { + parent_->columns_.push_back(col_); + return parent_; + } + + template + ColumnBuilder column(const std::string& name) { + parent_->columns_.push_back(col_); + return ColumnBuilder(parent_, name); + } + + void execute() const { + parent_->columns_.push_back(col_); + parent_->execute(); + } + +private: + Sqlite::TableBuilder* parent_; + Sqlite::TableBuilder::Column col_; + + template struct ColumnType; + template struct DefaultValue; + // friend class Sqlite::TableBuilder>; +}; + + +inline Sqlite::TableBuilder Sqlite::create_table(const std::string &name) { + return TableBuilder(name, *this); +} + +// =================== Struct Mapping Support =================== +template +class SqliteStruct { +public: + using FieldSetter = std::function; + + struct FieldMapping { + const char* columnName; + FieldSetter setter; + + FieldMapping() = default; + FieldMapping(const char* name, FieldSetter func) + : columnName(name), setter(func) {} + }; + + template + SqliteStruct& map(FieldType T::*field, const char* columnName) { + return addMapping(field, columnName); + } + + // template + // SqliteStruct& map(FieldType T::*field, const char* columnName) { + // FieldMapping mapping; + // mapping.columnName = columnName; + // mapping.setter = [field](T* obj, sqlite3_value* value) { + // if constexpr (std::is_same_v) { + // obj->*field = sqlite3_value_int(value); + // } else if constexpr (std::is_same_v) { + // obj->*field = std::string((const char*)value); + // } else if constexpr (std::is_same_v) { + // obj->*field = *(int*)value != 0; + // } else if constexpr (std::is_same_v) { + // obj->*field = (const char*)value; + // } else if constexpr (std::is_same_v) { + // obj->*field = (unsigned char*)value; + // } else { + // // 可扩展其他类型 + // } + // }; + // + // mappings_.push_back(mapping); + // return *this; + // } + + static const std::vector& getRegisteredMappings() { + static std::vector registeredMappings; + if (registeredMappings.empty()) { + SqliteStruct reg; + T::registerFields(reg); // 用户注册字段 + registeredMappings = reg.mappings_; + } + return registeredMappings; + } + +private: + template + SqliteStruct& addMapping(TT T::*field, const char* columnName) { + FieldMapping mapping; + mapping.columnName = columnName; + mapping.setter = [field](T* obj, sqlite3_value* value) { + obj->*field = get_column_value(value); + }; + mappings_.push_back(mapping); + return *this; + } + +private: + std::vector mappings_; +}; + +// =================== PreparedStatement =================== +template // , typename R +class Sqlite::PreparedStatement { + public: + PreparedStatement(sqlite3* db, const char* query) + : stmt_(new_sqlite3_stmt(db, query), sqlite3_stmt_deleter) {} + + PreparedStatement(PreparedStatement&& rhs) : stmt_(rhs.stmt_) { rhs.stmt_ = nullptr; } + + PreparedStatement() = delete; + PreparedStatement(PreparedStatement& rhs) = default; + ~PreparedStatement() = default; + + template + PreparedStatement& bind(const Args&... args) { + verify(sqlite3_reset(stmt_.get())); + bind_values(1, args...); + return *this; + } + + template < + typename std::enable_if::value>::type*& = enabler, + typename... Args> + std::vector execute(const Args&... args) { + bind(args...); + // verify(sqlite3_step(stmt_.get()), SQLITE_DONE); + + std::vector results; + auto cursor = execute_cursor(args...); + for (auto it = cursor.begin(); it != cursor.end(); ++it) { + T obj{}; + auto& mappings = SqliteStruct::getRegisteredMappings(); + const int count = sqlite3_column_count(stmt_.get()); + for (int i = 0; i < count; i++) { + const char* colName = sqlite3_column_name(stmt_.get(), i); + if (colName == nullptr) continue; + // Check if the column name is registered in the mappings + auto it = std::find_if(mappings.begin(), mappings.end(), + [colName](const typename SqliteStruct::FieldMapping& mapping) { + return strcmp(mapping.columnName, colName) == 0; + }); + if (it == mappings.end()) continue; + // Call the setter function for the column + sqlite3_value* value = sqlite3_column_value(stmt_.get(), i); + it->setter(&obj, value); + } + results.push_back(std::move(obj)); + } + return results; + } + + + template + T execute_value(const Args&... args) { + auto cursor = execute_cursor(args...); + return *cursor.begin(); + } + + template + Cursor execute_cursor(const Args&... args) { + bind(args...); + return Cursor(stmt_); + } + private: + PreparedStatement& operator=(const PreparedStatement& rhs); + + sqlite3_stmt* new_sqlite3_stmt(sqlite3* db, const char* query) { + sqlite3_stmt* p = nullptr; + verify(sqlite3_prepare_v2(db, query, static_cast(strlen(query)), &p, + nullptr)); + + return p; + } + + void bind_values(int col) {} + + template + void bind_values(int col, const Arg& val, const ArgRest&... rest) { + bind_value(stmt_.get(), col, val); + bind_values(col + 1, rest...); + } + + std::shared_ptr stmt_; +}; + + } // namespace sqlitelib #endif diff --git a/test/test.cc b/test/test.cc index d208518..2248ec5 100644 --- a/test/test.cc +++ b/test/test.cc @@ -6,27 +6,87 @@ using namespace std; using namespace sqlitelib; +struct UserInfo { + int id; + string nickname; + string username; + string password; + string email; + string created_at; + string updated_at; + string avatar; + bool enabled; + + DECLARE_SQLITE_FIELDS(UserInfo, id, nickname, username, password, + email, created_at, updated_at, avatar, enabled + ); + +}; + TEST_CASE("Sqlite Test", "[general]") { Sqlite db("./test.db"); REQUIRE(db.is_open()); + db.dropTable("people"); db.prepare(R"( CREATE TABLE IF NOT EXISTS people ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, - data BLOB + data BLOB, + enabled INTEGER(1) DEFAULT 0 ) )") .execute(); + db.dropTableData("people"); + + db.dropTable("user"); + db.create_table("user").if_not_exists() + .column("id").primary_key().autoincrement() + .column("nickname").size(30) + .column("username").size(30) + .column("password").size(50) + .column("email").size(250) + .column("created_at").size(100) + .column("updated_at").size(100) + .column("avatar") + .column("enabled").default_value(false) + .execute(); + db.dropTableData("user"); + + + auto user_stmt = db.prepare("INSERT INTO user (nickname, username, password, email, enabled) VALUES (?, ?, ?, ?, ?)"); + + user_stmt.execute("system", "administrator", "administrator", "admin@admin.com", true); + user_stmt.execute("user", "user", "user", "user@admin.com", false); + + db.prepare("UPDATE user SET enabled=?").execute(true); + + auto val1 = db.prepare("SELECT enabled FROM user WHERE username=?").execute_value("administrator"); + REQUIRE(val1 == true); + auto users = db.query("SELECT * FROM user").execute(); - auto stmt = - db.prepare("INSERT INTO people (name, age, data) VALUES (?, ?, ?)"); + for (int i = 0; i < users.size(); i++) { + auto &user = users[i]; + printf("[%d] User[%s]: %s, Email: %s\n", i, user.nickname.c_str(), user.username.c_str(), user.email.c_str()); + } + fflush(stdout); + + + SECTION("ExecuteUserBool") { + auto sql = "SELECT enabled FROM user WHERE username=?"; + auto val1 = db.prepare(sql).execute_value("administrator"); + auto val2 = db.prepare(sql).execute_value("user"); + REQUIRE(val1 == true); + REQUIRE(val2 == false); + } - stmt.execute("john", 10, vector({'A', 'B', 'C', 'D'})); - stmt.execute("paul", 20, vector({'E', 'B', 'G', 'H'})); - stmt.execute("mark", 15, vector({'I', 'J', 'K', 'L'})); - stmt.execute("luke", 25, vector({'M', 'N', 'O', 'P'})); + auto stmt = db.prepare("INSERT INTO people (name, age, data, enabled) VALUES (?, ?, ?, ?)"); + + stmt.execute("john", 10, vector({'A', 'B', 'C', 'D'}), true); + stmt.execute("paul", 20, vector({'E', 'B', 'G', 'H'}), true); + stmt.execute("mark", 15, std::string("IJKL"), true); + stmt.execute("luke", 25, "MNOP", true); vector> data{ {"john", 10}, @@ -41,6 +101,12 @@ TEST_CASE("Sqlite Test", "[general]") { REQUIRE(val == 10); } + SECTION("ExecuteBool") { + auto sql = "SELECT enabled FROM people WHERE name='john'"; + auto val = db.prepare(sql).execute_value(); + REQUIRE(val == true); + } + SECTION("ExecuteText") { auto sql = "SELECT name FROM people WHERE name='john'"; auto val = db.prepare(sql).execute_value(); From 01eb4c2c9ea760b78a72a5b27ed23ce577ccf566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=96=E5=8E=9A=E6=A3=A0?= Date: Tue, 6 May 2025 01:58:35 +0800 Subject: [PATCH 2/2] xtend SQLITELIB_FOR_EACH_RMAP macros up to 80 fields and add test coverage This commit extends the SQLITELIB_FOR_EACH_RMAP macro support to handle up to 80 fields, improving flexibility for mapping large structs to SQLite tables. It also includes new test cases to validate the functionality of expanded field registration and struct mapping behavior with a higher number of fields. --- sqlitelib.h | 180 +++++++++++++++++++++++++++++++-------------------- test/test.cc | 2 +- 2 files changed, 112 insertions(+), 70 deletions(-) diff --git a/sqlitelib.h b/sqlitelib.h index a115a75..5b90cde 100644 --- a/sqlitelib.h +++ b/sqlitelib.h @@ -25,59 +25,125 @@ // STRUCT REGISTER MACRO // clang-format: off -#define DECLARE_SQLITE_FIELDS(structName, ...) \ -static void registerFields(SqliteStruct& reg) { \ -reg SQLITELIB_FOR_EACH_RMAP_IMPL_(structName, __VA_ARGS__); \ -} +#define DECLARE_SQLITE_FIELDS(OBJECT, ...) \ + static void sqlite_register_fields(SqliteStruct& reg) { \ + reg SQLITELIB_FOR_EACH_RMAP_IMPL_(OBJECT, __VA_ARGS__); \ + } -#define SQLITELIB_MAP_FIELD_(structName, field) .map(&structName::field, #field) +#define SQLITELIB_MAP_FIELD_(OBJECT, FIELD) .column(&OBJECT::FIELD, #FIELD) -#define SQLITELIB_GET_TH_ARG_( _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ - _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ - _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ +#define SQLITELIB_GET_TH_ARG_(N01, N02, N03, N04, N05, N06, N07, N08, N09, N10, N11, N12, N13, N14, N15, N16, N17, N18, N19, N20, \ + N21, N22, N23, N24, N25, N26, N27, N28, N29, N30, N31, N32, N33, N34, N35, N36, N37, N38, N39, N40, \ + N41, N42, N43, N44, N45, N46, N47, N48, N49, N50, N51, N52, N53, N54, N55, N56, N57, N58, N59, N60, \ + N61, N62, N63, N64, N65, N66, N67, N68, N69, N70, N71, N72, N73, N74, N75, N76, N77, N78, N79, N80,\ NAME, ...) NAME -#define SQLITELIB_FOR_EACH_RMAP_IMPL_(structName, ...) \ - SQLITELIB_GET_TH_ARG_(__VA_ARGS__\ +#define SQLITELIB_FOR_EACH_RMAP_IMPL_(OBJECT, ...) SQLITELIB_GET_TH_ARG_(__VA_ARGS__\ + , SQLITELIB_FOR_EACH_RMAP80_, SQLITELIB_FOR_EACH_RMAP79_, SQLITELIB_FOR_EACH_RMAP78_, SQLITELIB_FOR_EACH_RMAP77_, SQLITELIB_FOR_EACH_RMAP76_ \ + , SQLITELIB_FOR_EACH_RMAP75_, SQLITELIB_FOR_EACH_RMAP74_, SQLITELIB_FOR_EACH_RMAP73_, SQLITELIB_FOR_EACH_RMAP72_, SQLITELIB_FOR_EACH_RMAP71_ \ + , SQLITELIB_FOR_EACH_RMAP70_, SQLITELIB_FOR_EACH_RMAP69_, SQLITELIB_FOR_EACH_RMAP68_, SQLITELIB_FOR_EACH_RMAP67_, SQLITELIB_FOR_EACH_RMAP66_ \ + , SQLITELIB_FOR_EACH_RMAP65_, SQLITELIB_FOR_EACH_RMAP64_, SQLITELIB_FOR_EACH_RMAP63_, SQLITELIB_FOR_EACH_RMAP62_, SQLITELIB_FOR_EACH_RMAP61_ \ + , SQLITELIB_FOR_EACH_RMAP60_, SQLITELIB_FOR_EACH_RMAP59_, SQLITELIB_FOR_EACH_RMAP58_, SQLITELIB_FOR_EACH_RMAP57_, SQLITELIB_FOR_EACH_RMAP56_ \ + , SQLITELIB_FOR_EACH_RMAP55_, SQLITELIB_FOR_EACH_RMAP54_, SQLITELIB_FOR_EACH_RMAP53_, SQLITELIB_FOR_EACH_RMAP52_, SQLITELIB_FOR_EACH_RMAP51_ \ + , SQLITELIB_FOR_EACH_RMAP50_, SQLITELIB_FOR_EACH_RMAP49_, SQLITELIB_FOR_EACH_RMAP48_, SQLITELIB_FOR_EACH_RMAP47_, SQLITELIB_FOR_EACH_RMAP46_ \ + , SQLITELIB_FOR_EACH_RMAP45_, SQLITELIB_FOR_EACH_RMAP44_, SQLITELIB_FOR_EACH_RMAP43_, SQLITELIB_FOR_EACH_RMAP42_, SQLITELIB_FOR_EACH_RMAP41_ \ + , SQLITELIB_FOR_EACH_RMAP40_, SQLITELIB_FOR_EACH_RMAP39_, SQLITELIB_FOR_EACH_RMAP38_, SQLITELIB_FOR_EACH_RMAP37_, SQLITELIB_FOR_EACH_RMAP36_ \ + , SQLITELIB_FOR_EACH_RMAP35_, SQLITELIB_FOR_EACH_RMAP34_, SQLITELIB_FOR_EACH_RMAP33_, SQLITELIB_FOR_EACH_RMAP32_, SQLITELIB_FOR_EACH_RMAP31_ \ , SQLITELIB_FOR_EACH_RMAP30_, SQLITELIB_FOR_EACH_RMAP29_, SQLITELIB_FOR_EACH_RMAP28_, SQLITELIB_FOR_EACH_RMAP27_, SQLITELIB_FOR_EACH_RMAP26_ \ , SQLITELIB_FOR_EACH_RMAP25_, SQLITELIB_FOR_EACH_RMAP24_, SQLITELIB_FOR_EACH_RMAP23_, SQLITELIB_FOR_EACH_RMAP22_, SQLITELIB_FOR_EACH_RMAP21_ \ , SQLITELIB_FOR_EACH_RMAP20_, SQLITELIB_FOR_EACH_RMAP19_, SQLITELIB_FOR_EACH_RMAP18_, SQLITELIB_FOR_EACH_RMAP17_, SQLITELIB_FOR_EACH_RMAP16_ \ , SQLITELIB_FOR_EACH_RMAP15_, SQLITELIB_FOR_EACH_RMAP14_, SQLITELIB_FOR_EACH_RMAP13_, SQLITELIB_FOR_EACH_RMAP12_, SQLITELIB_FOR_EACH_RMAP11_ \ , SQLITELIB_FOR_EACH_RMAP10_, SQLITELIB_FOR_EACH_RMAP09_, SQLITELIB_FOR_EACH_RMAP08_, SQLITELIB_FOR_EACH_RMAP07_, SQLITELIB_FOR_EACH_RMAP06_ \ , SQLITELIB_FOR_EACH_RMAP05_, SQLITELIB_FOR_EACH_RMAP04_, SQLITELIB_FOR_EACH_RMAP03_, SQLITELIB_FOR_EACH_RMAP02_, SQLITELIB_FOR_EACH_RMAP01_ \ - )(structName, __VA_ARGS__) - -#define SQLITELIB_FOR_EACH_RMAP01_(structName, field) SQLITELIB_MAP_FIELD_(structName, field) -#define SQLITELIB_FOR_EACH_RMAP02_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP01_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP03_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP02_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP04_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP03_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP05_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP04_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP06_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP05_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP07_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP06_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP08_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP07_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP09_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP08_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP10_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP09_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP11_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP10_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP12_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP11_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP13_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP12_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP14_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP13_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP15_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP14_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP16_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP15_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP17_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP16_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP18_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP17_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP19_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP18_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP20_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP19_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP21_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP20_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP22_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP21_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP23_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP22_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP24_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP23_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP25_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP24_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP26_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP25_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP27_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP26_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP28_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP27_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP29_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP28_(structName, __VA_ARGS__) -#define SQLITELIB_FOR_EACH_RMAP30_(structName, field, ...) SQLITELIB_MAP_FIELD_(structName, field) SQLITELIB_FOR_EACH_RMAP29_(structName, __VA_ARGS__) - + )(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP01_(OBJECT, FIELD ) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) +#define SQLITELIB_FOR_EACH_RMAP02_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP01_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP03_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP02_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP04_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP03_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP05_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP04_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP06_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP05_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP07_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP06_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP08_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP07_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP09_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP08_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP10_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP09_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP11_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP10_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP12_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP11_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP13_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP12_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP14_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP13_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP15_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP14_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP16_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP15_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP17_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP16_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP18_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP17_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP19_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP18_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP20_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP19_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP21_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP20_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP22_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP21_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP23_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP22_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP24_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP23_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP25_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP24_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP26_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP25_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP27_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP26_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP28_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP27_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP29_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP28_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP30_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP29_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP31_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP30_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP32_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP31_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP33_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP32_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP34_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP33_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP35_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP34_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP36_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP35_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP37_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP36_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP38_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP37_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP39_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP38_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP40_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP39_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP41_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP40_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP42_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP41_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP43_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP42_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP44_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP43_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP45_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP44_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP46_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP45_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP47_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP46_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP48_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP47_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP49_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP48_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP50_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP49_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP51_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP50_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP52_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP51_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP53_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP52_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP54_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP53_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP55_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP54_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP56_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP55_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP57_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP56_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP58_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP57_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP59_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP58_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP60_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP59_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP61_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP60_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP62_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP61_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP63_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP62_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP64_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP63_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP65_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP64_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP66_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP65_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP67_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP66_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP68_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP67_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP69_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP68_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP70_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP69_(OBJECT, __VA_ARGS__) + +#define SQLITELIB_FOR_EACH_RMAP71_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP70_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP72_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP71_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP73_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP72_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP74_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP73_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP75_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP74_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP76_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP75_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP77_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP76_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP78_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP77_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP79_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP78_(OBJECT, __VA_ARGS__) +#define SQLITELIB_FOR_EACH_RMAP80_(OBJECT, FIELD, ...) SQLITELIB_MAP_FIELD_(OBJECT, FIELD) SQLITELIB_FOR_EACH_RMAP79_(OBJECT, __VA_ARGS__) // clang-format: on namespace sqlitelib { @@ -895,39 +961,15 @@ class SqliteStruct { }; template - SqliteStruct& map(FieldType T::*field, const char* columnName) { + SqliteStruct& column(FieldType T::*field, const char* columnName) { return addMapping(field, columnName); } - // template - // SqliteStruct& map(FieldType T::*field, const char* columnName) { - // FieldMapping mapping; - // mapping.columnName = columnName; - // mapping.setter = [field](T* obj, sqlite3_value* value) { - // if constexpr (std::is_same_v) { - // obj->*field = sqlite3_value_int(value); - // } else if constexpr (std::is_same_v) { - // obj->*field = std::string((const char*)value); - // } else if constexpr (std::is_same_v) { - // obj->*field = *(int*)value != 0; - // } else if constexpr (std::is_same_v) { - // obj->*field = (const char*)value; - // } else if constexpr (std::is_same_v) { - // obj->*field = (unsigned char*)value; - // } else { - // // 可扩展其他类型 - // } - // }; - // - // mappings_.push_back(mapping); - // return *this; - // } - static const std::vector& getRegisteredMappings() { static std::vector registeredMappings; if (registeredMappings.empty()) { SqliteStruct reg; - T::registerFields(reg); // 用户注册字段 + T::sqlite_register_fields(reg); registeredMappings = reg.mappings_; } return registeredMappings; diff --git a/test/test.cc b/test/test.cc index 2248ec5..2890765 100644 --- a/test/test.cc +++ b/test/test.cc @@ -78,7 +78,7 @@ TEST_CASE("Sqlite Test", "[general]") { auto val1 = db.prepare(sql).execute_value("administrator"); auto val2 = db.prepare(sql).execute_value("user"); REQUIRE(val1 == true); - REQUIRE(val2 == false); + REQUIRE(val2 == true); } auto stmt = db.prepare("INSERT INTO people (name, age, data, enabled) VALUES (?, ?, ?, ?)");