17#ifndef DAISI_LOGGING_DEFINITIONS_H_
18#define DAISI_LOGGING_DEFINITIONS_H_
28#include <unordered_set>
31using LogDeviceApp = std::function<void(
const std::string &)>;
34using LogFunction = std::function<void(
const std::string &)>;
37using LogEvent = std::function<void(
const std::string &, uint8_t,
const std::string &)>;
45template <
typename... Tp>
inline std::string toSQL(
const std::string &format_str, Tp... values) {
47 int len = snprintf(
nullptr, 0, format_str.c_str(), values...);
49 throw std::runtime_error(
"Unable to format SQL statement!");
53 std::string statement;
54 statement.resize(len);
55 int rc = snprintf(statement.data(), len + 1, format_str.c_str(), values...);
57 throw std::runtime_error(
"Unable to format SQL statement!");
66 std::string format =
"NULL";
67 bool not_null =
false;
69 std::string foreign_key =
"";
70 bool is_primary_key =
false;
71 std::string data_type =
"INTEGER";
74 static const std::unordered_set<std::string> int_specifiers{
"%d",
"%i",
"%ld",
76 static const std::unordered_set<std::string> real_specifiers{
"%f",
"%lf"};
77 bool plain_string =
true;
78 std::string format_copy = format;
79 if (format.rfind(
"sql", 0) == 0) {
81 format_copy.erase(0, 3);
86 if (int_specifiers.count(format_copy) != 0) {
87 data_type =
"INTEGER";
88 }
else if (real_specifiers.count(format_copy) != 0) {
90 }
else if (format_copy ==
"%s") {
92 if (plain_string) format =
"'%s'";
93 }
else if (format_copy ==
"NULL") {
96 throw std::runtime_error(
"Unknown ColumnDataType");
114 std::string foreign_key =
"",
bool is_primary_key =
false)
115 : name(std::move(name)),
116 format(std::move(format)),
118 foreign_key(std::move(foreign_key)),
119 is_primary_key(is_primary_key) {
127 std::vector<DatabaseColumnInfo> columns;
128 std::string additional_constraints;
135 explicit DatabaseTable(std::string name, std::vector<DatabaseColumnInfo> columns = {},
136 std::string additional_constraints =
"")
137 : name(std::move(name)),
138 columns(std::move(columns)),
139 additional_constraints(std::move(additional_constraints)){};
145inline std::string getCreateTableStatement(
const DatabaseTable &table) {
146 std::ostringstream statement;
147 statement <<
"CREATE TABLE IF NOT EXISTS " << table.name <<
"(";
149 std::ostringstream foreign_keys;
153 for (
auto col_it = table.columns.begin(); col_it != table.columns.end(); col_it++) {
154 statement << col_it->name <<
" " << col_it->data_type;
156 statement <<
" NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE";
157 }
else if (col_it->is_primary_key) {
158 statement <<
" NOT NULL PRIMARY KEY UNIQUE";
159 }
else if (col_it->not_null) {
160 statement <<
" NOT NULL";
162 if (col_it->foreign_key.length() != 0U) {
164 foreign_keys <<
",FOREIGN KEY(" << col_it->name <<
") REFERENCES " << col_it->foreign_key;
167 if (col_it != --table.columns.end()) {
172 statement << foreign_keys.str();
173 if (!table.additional_constraints.empty()) {
174 statement <<
"," << table.additional_constraints;
178 return statement.str();
191inline std::string getCreateViewStatement(
192 const DatabaseTable &table,
const std::unordered_map<std::string, std::string> &replacements,
193 const std::vector<std::string> &joins,
const std::string &view_name =
"") {
194 std::ostringstream statement;
196 std::string final_view_name = view_name.empty() ?
"view" + table.name : view_name;
197 statement <<
"CREATE VIEW IF NOT EXISTS " << final_view_name <<
" AS SELECT ";
201 for (
auto col_it = table.columns.begin(); col_it != table.columns.end(); col_it++) {
202 auto repl = replacements.find(col_it->name);
203 if (repl != replacements.end()) {
204 if (!repl->second.empty()) {
206 statement << repl->second;
210 statement << table.name <<
"." << col_it->name;
214 if (col_it != --table.columns.end()) {
219 statement <<
" FROM " << table.name;
222 if (!joins.empty()) {
224 for (
auto join_it = joins.begin(); join_it != joins.end(); join_it++) {
225 statement << *join_it;
228 if (join_it != --joins.end()) {
235 return statement.str();
244template <
typename... Tp>
245std::string getInsertStatement(
const DatabaseTable &table,
const std::tuple<Tp...> &values) {
246 static constexpr bool kStringInTuple{(std::is_same_v<std::string, Tp> || ...)};
247 static_assert(!kStringInTuple,
248 "Error generating SQL Insert Statement: The tuple contains a string. "
249 "Convert the string to char array with .c_str() before calling!");
251 std::ostringstream statement;
252 statement <<
"INSERT INTO " << table.name <<
" VALUES(";
254 for (
auto col_it = table.columns.begin(); col_it != table.columns.end(); col_it++) {
255 statement << col_it->format;
257 if (col_it != --table.columns.end()) {
263 const std::string format_str = statement.str();
266 std::tuple<char *, int, const char *> buffer_format_tuple{
nullptr, 0, format_str.c_str()};
267 auto snprintf_args = std::tuple_cat(buffer_format_tuple, values);
269 int len = std::apply(snprintf, snprintf_args);
271 throw std::runtime_error(
"Unable to format SQL query!");
277 buffer_format_tuple = std::make_tuple(query.data(), len + 1, format_str.c_str());
278 snprintf_args = std::tuple_cat(buffer_format_tuple, values);
279 int rc = std::apply(snprintf, snprintf_args);
281 throw std::runtime_error(
"Unable to format SQL query!");
Definition definitions.h:63
DatabaseColumnInfo(std::string name)
Constructor for primary key id column.
Definition definitions.h:103
DatabaseColumnInfo(std::string name, std::string format, bool not_null=false, std::string foreign_key="", bool is_primary_key=false)
Constructor for regular and foreign key column.
Definition definitions.h:113
Definition definitions.h:124
DatabaseTable(std::string name, std::vector< DatabaseColumnInfo > columns={}, std::string additional_constraints="")
Constructor for a table definition.
Definition definitions.h:135