Skip to content

Commit

Permalink
Added convenience functions for constructing objects from a row
Browse files Browse the repository at this point in the history
  • Loading branch information
dend456 committed Feb 13, 2017
1 parent 92bbecc commit f01a644
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
17 changes: 17 additions & 0 deletions include/SQLiteCpp/Column.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,22 @@ class Column
*/
std::ostream& operator<<(std::ostream& aStream, const Column& aColumn);

#if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900)
// Create an instance of T from the first N columns, see declaration in Statement.h for full details
template<typename T, int N>
T Statement::getColumns()
{
checkRow();
checkIndex(N - 1);
return getColumns<T>(std::make_integer_sequence<int, N>{});
}

// Helper function called by getColums<typename T, int N>
template<typename T, const int... Is>
T Statement::getColumns(const std::integer_sequence<int, Is...>)
{
return T(Column(mStmtPtr, Is)...);
}
#endif

} // namespace SQLite
34 changes: 34 additions & 0 deletions include/SQLiteCpp/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,40 @@ class Statement
*/
Column getColumn(const char* apName);

#if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900)
/**
* @brief Return an instance of T constructed from copies of the first N columns
*
* Can be used to access the data of the current row of result when applicable,
* while the executeStep() method returns true.
*
* Throw an exception if there is no row to return a Column from:
* - if provided column count is out of bound
* - before any executeStep() call
* - after the last executeStep() returned false
* - after a reset() call
*
* Throw an exception if the specified column count is out of the [0, getColumnCount()) range.
*
* @tparam T Object type to construct
* @tparam N Number of columns
*
* @note Requires std=C++14
*/
template<typename T, int N>
T getColumns();

private:
/**
* @brief Helper function used by getColumns<typename T, int N> to expand an integer_sequence used to generate
* the required Column objects
*/
template<typename T, const int... Is>
T getColumns(const std::integer_sequence<int, Is...>);

public:
#endif

/**
* @brief Test if the column value is NULL
*
Expand Down
57 changes: 57 additions & 0 deletions tests/Statement_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,3 +651,60 @@ TEST(Statement, getName) {
EXPECT_EQ("msg", oname1);
#endif
}

#if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900)
TEST(Statement, getColumns) {
struct GetRowTestStruct
{
int id;
std::string msg;
int integer;
double real;
GetRowTestStruct(int _id, std::string _msg, int _integer, double _real)
: id(_id), msg(_msg), integer(_integer), real(_real)
{}

GetRowTestStruct(int _id, const std::string& _msg)
: id(_id), msg(_msg), integer(-1), real(0.0)
{}
};

// Create a new database
SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
EXPECT_EQ(SQLite::OK, db.getErrorCode());
EXPECT_EQ(SQLite::OK, db.getExtendedErrorCode());

// Create a new table
EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT, int INTEGER, double REAL)"));
EXPECT_EQ(SQLite::OK, db.getErrorCode());
EXPECT_EQ(SQLite::OK, db.getExtendedErrorCode());

// Create a first row
EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\", 123, 0.123)"));
EXPECT_EQ(1, db.getLastInsertRowid());
EXPECT_EQ(1, db.getTotalChanges());

// Compile a SQL query
SQLite::Statement query(db, "SELECT * FROM test");
EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str());
EXPECT_EQ(4, query.getColumnCount());
query.executeStep();
EXPECT_TRUE(query.isOk());
EXPECT_FALSE(query.isDone());

// Get all columns
auto testStruct = query.getColumns<GetRowTestStruct, 4>();
EXPECT_EQ(1, testStruct.id);
EXPECT_EQ("first", testStruct.msg);
EXPECT_EQ(123, testStruct.integer);
EXPECT_EQ(0.123, testStruct.real);

// Get only the first 2 columns
auto testStruct2 = query.getColumns<GetRowTestStruct, 2>();
EXPECT_EQ(1, testStruct2.id);
EXPECT_EQ("first", testStruct2.msg);
EXPECT_EQ(-1, testStruct2.integer);
EXPECT_EQ(0.0, testStruct2.real);
}
#endif

0 comments on commit f01a644

Please sign in to comment.