-
-
Notifications
You must be signed in to change notification settings - Fork 339
Expand file tree
/
Copy pathany.cpp
More file actions
168 lines (153 loc) · 6.29 KB
/
any.cpp
File metadata and controls
168 lines (153 loc) · 6.29 KB
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
* This example demonstrates how to use std::any as a mapped type.
* It is a bit more complex than the other examples, because it
* uses custom row_extractor and statement_binder.
* Please note that this implementation is not the one and only
* option of implementation of `std:any` binding to sqlite_orm.
* It is just an example of how to use std::any as a mapped type.
* Implementation is based on 5 types SQLite supports:
* NULL, INTEGER, REAL, TEXT, BLOB.
* NULL is mapped to std::nullopt.
* INTEGER is mapped to int.
* REAL is mapped to double.
* TEXT is mapped to std::string.
* BLOB is mapped to std::vector<char>.
*/
#include <sqlite_orm/sqlite_orm.h>
#ifdef __has_include
#if __has_include(<any>)
#include <any>
#endif
#endif
#if __cpp_lib_any >= 201606L
#define ENABLE_THIS_EXAMPLE
#endif
#ifdef ENABLE_THIS_EXAMPLE
#include <iostream>
#include <cstdio>
using namespace sqlite_orm;
using std::cout;
using std::endl;
namespace sqlite_orm {
template<>
struct row_extractor<std::any> {
std::any extract(sqlite3_stmt* stmt, int columnIndex) const {
const int type = sqlite3_column_type(stmt, columnIndex);
switch (type) {
case SQLITE_NULL:
return std::nullopt;
case SQLITE_INTEGER:
return sqlite3_column_int(stmt, columnIndex);
case SQLITE_FLOAT:
return sqlite3_column_double(stmt, columnIndex);
case SQLITE_TEXT: {
const unsigned char* text = sqlite3_column_text(stmt, columnIndex);
return std::string(reinterpret_cast<const char*>(text));
}
case SQLITE_BLOB: {
const void* blob = sqlite3_column_blob(stmt, columnIndex);
const int size = sqlite3_column_bytes(stmt, columnIndex);
return std::vector<char>(reinterpret_cast<const char*>(blob),
reinterpret_cast<const char*>(blob) + size);
}
default:
throw std::runtime_error("Unsupported SQLite column type for std::any");
}
}
std::any extract(sqlite3_value* value) const {
const int type = sqlite3_value_type(value);
switch (type) {
case SQLITE_NULL:
return std::nullopt;
case SQLITE_INTEGER:
return sqlite3_value_int(value);
case SQLITE_FLOAT:
return sqlite3_value_double(value);
case SQLITE_TEXT: {
const unsigned char* text = sqlite3_value_text(value);
return std::string(reinterpret_cast<const char*>(text));
}
case SQLITE_BLOB: {
const void* blob = sqlite3_value_blob(value);
const int size = sqlite3_value_bytes(value);
return std::vector<char>(reinterpret_cast<const char*>(blob),
reinterpret_cast<const char*>(blob) + size); // Handle BLOB
}
default:
throw std::runtime_error("Unsupported SQLite value type for std::any");
}
}
};
template<>
struct statement_binder<std::any> {
int bind(sqlite3_stmt* stmt, int index, const std::any& value) const {
if (!value.has_value()) {
return sqlite3_bind_null(stmt, index);
}
if (value.type() == typeid(int)) {
return sqlite3_bind_int(stmt, index, std::any_cast<int>(value));
} else if (value.type() == typeid(double)) {
return sqlite3_bind_double(stmt, index, std::any_cast<double>(value));
} else if (value.type() == typeid(std::string)) {
const auto& text = std::any_cast<std::string>(value);
return sqlite3_bind_text(stmt, index, text.c_str(), static_cast<int>(text.size()), SQLITE_TRANSIENT);
} else if (value.type() == typeid(std::vector<char>)) {
const auto& blob = std::any_cast<std::vector<char>>(value);
return sqlite3_bind_blob(stmt, index, blob.data(), static_cast<int>(blob.size()), SQLITE_TRANSIENT);
}
return SQLITE_MISMATCH;
}
};
template<>
struct type_printer<std::any> : public text_printer {};
template<>
struct field_printer<std::any> {
std::string operator()(const std::any& value) const {
if (!value.has_value()) {
return "NULL";
}
if (value.type() == typeid(int)) {
return std::to_string(std::any_cast<int>(value));
} else if (value.type() == typeid(double)) {
return std::to_string(std::any_cast<double>(value));
} else if (value.type() == typeid(std::string)) {
return std::any_cast<std::string>(value);
} else if (value.type() == typeid(std::vector<char>)) {
const auto& blob = std::any_cast<std::vector<char>>(value);
std::ostringstream oss;
oss << "0x";
for (unsigned char c: blob) {
oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c);
}
return oss.str();
}
throw std::runtime_error("Unsupported type in std::any field_printer");
}
};
}
#endif
int main() {
#ifdef ENABLE_THIS_EXAMPLE
struct Value {
int id = 0;
std::any value;
};
auto filename = "any.sqlite";
::remove(filename);
auto storage = make_storage(
filename,
make_table("test", make_column("id", &Value::id, primary_key()), make_column("value", &Value::value)));
storage.sync_schema();
storage.replace(Value{1, std::any{1}});
storage.replace(Value{2, std::any{2.5}});
storage.replace(Value{3, std::any{std::string("Hello, world!")}});
storage.replace(
Value{4, std::any{std::vector<char>{'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'}}});
cout << "Test:" << endl;
for (auto& test: storage.iterate<Value>()) {
cout << storage.dump(test) << endl;
}
cout << endl;
#endif
return 0;
}