auto r2 = db.Exec(q);
ASSERT_TRUE(static_cast<bool>(r2));
}
+
+ void SetDefaultWithNull() {
+ tizen_base::Database db(TEST_DB, SQLITE_OPEN_READWRITE);
+ auto q = tizen_base::Database::Sql(Q_INSERT)
+ .Bind(std::nullopt)
+ .Bind(1234)
+ .Bind(9.216)
+ .Bind(std::nullopt);
+
+ auto r1 = db.Exec(q);
+ ASSERT_TRUE(static_cast<bool>(r1));
+ auto r2 = db.Exec(q);
+ ASSERT_TRUE(static_cast<bool>(r2));
+ }
};
TEST_F(DatabaseTest, test_insert) {
EXPECT_TRUE(static_cast<bool>(r));
}
+TEST_F(DatabaseTest, test_insert_name_and_data_with_null) {
+ tizen_base::Database db(TEST_DB, SQLITE_OPEN_READWRITE);
+ auto q = tizen_base::Database::Sql(Q_INSERT_NAME)
+ .Bind(":name", std::nullopt)
+ .Bind(":num", 1234)
+ .Bind(":val", 9.216)
+ .Bind(":data", std::nullopt);
+ auto r = db.Exec(q);
+
+ EXPECT_TRUE(static_cast<bool>(r));
+}
+
TEST_F(DatabaseTest, test_select) {
SetDefault();
using tizen_base::_;
EXPECT_EQ(static_cast<std::string>(name), "gogo");
EXPECT_EQ(static_cast<int>(num), 1234);
EXPECT_EQ(static_cast<double>(val), 9.216);
- std::vector<unsigned char> v = data;
+ auto v = static_cast<std::vector<unsigned char>>(data);
EXPECT_EQ(v.size(), 4);
EXPECT_EQ(v[0], '9');
EXPECT_EQ(v[1], '2');
EXPECT_TRUE(static_cast<bool>(r));
for (const auto& i : r) {
- std::string name = i.Get(0);
- double val = i.Get(2);
+ std::string name = static_cast<std::string>(i.Get(0));
+ double val = static_cast<double>(i.Get(2));
EXPECT_EQ(name, "gogo");
EXPECT_EQ(val, 9.216);
}
}
+TEST_F(DatabaseTest, test_select3) {
+ SetDefaultWithNull();
+ using tizen_base::_;
+ tizen_base::Database db(TEST_DB, SQLITE_OPEN_READWRITE);
+ auto r = db.Exec({ Q_SELECT });
+
+ EXPECT_TRUE(static_cast<bool>(r));
+ for (const auto& i : r) {
+ std::optional<std::string> name = i.Get(0);
+ double val = static_cast<double>(i.Get(2));
+ std::optional<std::vector<unsigned char>> data = i.Get(3);
+ EXPECT_FALSE(name);
+ EXPECT_EQ(val, 9.216);
+ EXPECT_FALSE(data);
+ }
+}
+
TEST_F(DatabaseTest, test_ToVector) {
SetDefault();
void operator () (const tizen_base::Database::Result::Record& rec) {
Name = static_cast<std::string>(rec.Get(0));
- Num = rec.Get(1);
- Val = rec.Get(2);
- Data = rec.Get(3);
+ Num = static_cast<int>(rec.Get(1));
+ Val = static_cast<double>(rec.Get(2));
+ Data = static_cast<std::vector<unsigned char>>(rec.Get(3));
}
};
void operator () (const tizen_base::Database::Result::Record& rec) {
Name = static_cast<std::string>(rec.Get(0));
- Num = rec.Get(1);
- Val = rec.Get(2);
- Data = rec.Get(3);
+ Num = static_cast<int>(rec.Get(1));
+ Val = static_cast<double>(rec.Get(2));
+ Data = static_cast<std::vector<unsigned char>>(rec.Get(3));
}
};
void operator () (const tizen_base::Database::Result::Record& rec) {
Name = static_cast<std::string>(rec.Get(0));
- Num = rec.Get(1);
- Val = rec.Get(2);
- Data = rec.Get(3);
+ Num = static_cast<int>(rec.Get(1));
+ Val = static_cast<double>(rec.Get(2));
+ Data = static_cast<std::vector<unsigned char>>(rec.Get(3));
}
};
auto rec = r.GetFirstRecord();
EXPECT_TRUE(rec);
- std::string name = rec->Get(0);
- double val = rec->Get(2);
+ std::string name = static_cast<std::string>(rec->Get(0));
+ double val = static_cast<double>(rec->Get(2));
EXPECT_EQ(name, "gogo");
EXPECT_EQ(val, 9.216);
}
}
```
-### Bind
+### Binding
- Bind() method supports various data type such as std::string, int, double and std::vector<unsigned char>.
```cpp
.Bind(":data", std::vector<unsigned char> {'9', '2', '1', '6' });
```
+### Null-type binding
+- Null-type binding is supported using 'std::nullopt'.
+
+```cpp
+ tizen_base::Database db("test.db", SQLITE_OPEN_READWRITE);
+ auto q = tizen_base::Database::Sql(
+ "INSERT INTO TestTable(name, num, val, data) VALUES (?, ?, ?, ?);")
+ .Bind(std::nullopt)
+ .Bind(1234)
+ .Bind(9.216)
+ .Bind(std::nullopt);
+```
+- To get nullable object, you can use 'std::optional<>'.
+```cpp
+ for (const auto& i : r) {
+ std::optional<std::string> name = i.Get(0);
+ double val = static_cast<double>(i.Get(2));
+ std::optional<std::vector<unsigned char>> data = i.Get(3);
+ ...
+ }
+```
+
### Structured binding declaration
```cpp
auto [name, num, val, data] = i.Get<_, _, _, _>();
- There are many conversion operators to get the value.
```cpp
for (const auto& i : db.Exec({ "SELECT name, num, val, data FROM TestTable;" })) {
- std::string name = i.Get(0);
- int num = i.Get(1);
- double val = i.Get(2);
- std::vector<unsigned char> data = i.Get(3);
+ auto name = static_cast<std::string>(i.Get(0));
+ auto num = static_cast<int>(i.Get(1));
+ auto val = static_cast<double>(i.Get(2));
+ auto data = static_cast<std::vector<unsigned char>>(i.Get(3));
}
```
// It should be implemented to map data set
void operator () (const tizen_base::Database::Result::Record& rec) {
Id = static_cast<std::string>(rec.Get(0));
- Val = rec.Get(1);
+ Val = static_cast<int>(rec.Get(1));
}
};
#include <list>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
for_(func, std::make_index_sequence<N>());
}
-using DbType = std::variant<int, double, std::string,
- std::vector<unsigned char>>;
+using DbType = std::optional<std::variant<int, double, std::string,
+ std::vector<unsigned char>>>;
class AutoDbType {
public:
AutoDbType() = default;
AutoDbType(DbType db_type) : db_type_(db_type) {}
- operator int () {
- return std::get<int>(db_type_);
+ explicit operator int () {
+ if (!db_type_)
+ throw std::runtime_error("invalid type conversion from nullopt to int");
+ return std::get<int>(*db_type_);
}
- operator std::string () {
- return std::get<std::string>(db_type_);
+ explicit operator std::string () {
+ if (!db_type_) {
+ throw std::runtime_error(
+ "invalid type conversion from nullopt to string");
+ }
+
+ return std::get<std::string>(*db_type_);
+ }
+
+ explicit operator double () {
+ if (!db_type_) {
+ throw std::runtime_error(
+ "invalid type conversion from nullopt to double");
+ }
+
+ return std::get<double>(*db_type_);
+ }
+
+ explicit operator std::vector<unsigned char> () {
+ if (!db_type_) {
+ throw std::runtime_error(
+ "invalid type conversion from nullopt to std::vector<unsigned char>");
+ }
+
+ return std::get<std::vector<unsigned char>>(*db_type_);
}
- operator double () {
- return std::get<double>(db_type_);
+ operator std::optional<int> () {
+ if (!db_type_)
+ return std::nullopt;
+ return std::get<int>(*db_type_);
+ }
+
+ operator std::optional<std::string> () {
+ if (!db_type_)
+ return std::nullopt;
+ return std::get<std::string>(*db_type_);
}
- operator std::vector<unsigned char> () {
- return std::get<std::vector<unsigned char>>(db_type_);
+ operator std::optional<double> () {
+ if (!db_type_)
+ return std::nullopt;
+ return std::get<double>(*db_type_);
+ }
+
+ operator std::optional<std::vector<unsigned char>> () {
+ if (!db_type_)
+ return std::nullopt;
+ return std::get<std::vector<unsigned char>>(*db_type_);
}
private:
return *this;
}
+ Sql& Bind(const std::nullopt_t val) {
+ bindings_.push_back(DbType(val));
+ return *this;
+ }
+
Sql& Bind(int pos, std::string val) {
binding_map_[pos] = DbType(std::move(val));
return *this;
return *this;
}
+ Sql& Bind(int pos, const std::nullopt_t& val) {
+ binding_map_[pos] = DbType(val);
+ return *this;
+ }
+
Sql& Bind(std::string name, std::string val) {
binding_name_map_[std::move(name)] = DbType(std::move(val));
return *this;
return *this;
}
+ Sql& Bind(std::string name, const std::nullopt_t& val) {
+ binding_name_map_[std::move(name)] = DbType(val);
+ return *this;
+ }
+
const std::vector<DbType>& GetBindings() const {
return bindings_;
}
AutoDbType Get(int pos) const {
sqlite3_stmt* stmt = const_cast<sqlite3_stmt*>(stmt_);
int type = sqlite3_column_type(stmt, pos);
- if (type == SQLITE_NULL)
- throw std::runtime_error("invalid column");
DbType dbt;
if (type == SQLITE_TEXT) {
} else {
dbt = DbType(std::vector<unsigned char>(val, val + len));
}
+ } else if (type == SQLITE_NULL) {
+ dbt = DbType(std::nullopt);
} else {
throw std::runtime_error("invalid column type");
}
private:
void Bind(int pos, const DbType& type, sqlite3_stmt* stmt) const {
int r;
- if (const std::string* pstr = std::get_if<std::string>(&type)) {
+ if (!type) {
+ r = sqlite3_bind_null(stmt, pos);
+ if (r != SQLITE_OK) {
+ throw std::runtime_error("Invalid binding");
+ }
+
+ return;
+ }
+
+ if (const std::string* pstr = std::get_if<std::string>(&(*type))) {
r = sqlite3_bind_text(stmt, pos, (*pstr).c_str(), -1,
SQLITE_TRANSIENT);
- } else if (const int* pint = std::get_if<int>(&type)) {
+ } else if (const int* pint = std::get_if<int>(&(*type))) {
r = sqlite3_bind_int(stmt, pos, (*pint));
- } else if (const double* pdouble = std::get_if<double>(&type)) {
+ } else if (const double* pdouble = std::get_if<double>(&(*type))) {
r = sqlite3_bind_double(stmt, pos, (*pdouble));
} else if (const std::vector<unsigned char>* pvector =
- std::get_if<std::vector<unsigned char>>(&type)) {
+ std::get_if<std::vector<unsigned char>>(&(*type))) {
r = sqlite3_bind_blob(stmt, pos, (*pvector).data(),
(*pvector).size(), nullptr);
} else {