implemented sqlite fetch
This commit is contained in:
parent
d76ac60278
commit
7c1e940814
|
|
@ -31,6 +31,8 @@ public:
|
||||||
|
|
||||||
size_t execute(const std::string &stmt) override;
|
size_t execute(const std::string &stmt) override;
|
||||||
|
|
||||||
|
sql::record describe(const std::string& table) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int parse_result(void* param, int column_count, char** values, char** columns);
|
static int parse_result(void* param, int column_count, char** values, char** columns);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ namespace matador::backends::sqlite {
|
||||||
|
|
||||||
class sqlite_query_result : public sql::query_result_impl {
|
class sqlite_query_result : public sql::query_result_impl {
|
||||||
public:
|
public:
|
||||||
|
~sqlite_query_result() override;
|
||||||
|
|
||||||
void read_value(const char *id, size_t index, char &value) override;
|
void read_value(const char *id, size_t index, char &value) override;
|
||||||
void read_value(const char *id, size_t index, short &value) override;
|
void read_value(const char *id, size_t index, short &value) override;
|
||||||
void read_value(const char *id, size_t index, int &value) override;
|
void read_value(const char *id, size_t index, int &value) override;
|
||||||
|
|
@ -25,9 +27,10 @@ public:
|
||||||
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value) override;
|
void read_value(const char *id, size_t index, std::string &value) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
||||||
|
void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override;
|
||||||
|
|
||||||
protected:
|
[[nodiscard]] const char* column(size_t index) const override;
|
||||||
[[nodiscard]] bool next_row() override;
|
[[nodiscard]] bool fetch() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class sqlite_connection;
|
friend class sqlite_connection;
|
||||||
|
|
@ -40,8 +43,7 @@ private:
|
||||||
using rows = std::vector<columns>;
|
using rows = std::vector<columns>;
|
||||||
|
|
||||||
rows result_;
|
rows result_;
|
||||||
size_t row_index_ = 0;
|
long long row_index_ = -1;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
#include "sqlite_error.hpp"
|
#include "sqlite_error.hpp"
|
||||||
#include "sqlite_query_result.hpp"
|
#include "sqlite_query_result.hpp"
|
||||||
|
|
||||||
#include <utility>
|
#include "matador/sql/record.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace matador::backends::sqlite {
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
|
|
@ -40,6 +42,11 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values
|
||||||
auto *result = static_cast<sqlite_query_result*>(param);
|
auto *result = static_cast<sqlite_query_result*>(param);
|
||||||
result->push_back(values, column_count);
|
result->push_back(values, column_count);
|
||||||
|
|
||||||
|
sql::record prototype;
|
||||||
|
for(int i = 0; i < column_count; ++i) {
|
||||||
|
prototype.append(sql::column{columns[i]});
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +64,7 @@ std::unique_ptr<sql::query_result_impl> sqlite_connection::fetch(const std::stri
|
||||||
{
|
{
|
||||||
auto result = std::make_unique<sqlite_query_result>();
|
auto result = std::make_unique<sqlite_query_result>();
|
||||||
char *errmsg = nullptr;
|
char *errmsg = nullptr;
|
||||||
int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, result.get(), &errmsg);
|
const int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, result.get(), &errmsg);
|
||||||
|
|
||||||
throw_sqlite_error(ret, sqlite_db_, "sqlite", stmt);
|
throw_sqlite_error(ret, sqlite_db_, "sqlite", stmt);
|
||||||
|
|
||||||
|
|
@ -68,6 +75,69 @@ void sqlite_connection::prepare(const std::string &stmt)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sql::data_type_t string2type(const char *type)
|
||||||
|
{
|
||||||
|
if (strncmp(type, "INTEGER", 7) == 0) {
|
||||||
|
return sql::data_type_t::type_int;
|
||||||
|
} else if (strncmp(type, "TINYINT", 7) == 0) {
|
||||||
|
return sql::data_type_t::type_char;
|
||||||
|
} else if (strncmp(type, "SMALLINT", 8) == 0) {
|
||||||
|
return sql::data_type_t::type_short;
|
||||||
|
} else if (strncmp(type, "BIGINT", 6) == 0) {
|
||||||
|
return sql::data_type_t::type_long_long;
|
||||||
|
} else if (strcmp(type, "BOOLEAN") == 0) {
|
||||||
|
return sql::data_type_t::type_bool;
|
||||||
|
} else if (strcmp(type, "REAL") == 0) {
|
||||||
|
return sql::data_type_t::type_double;
|
||||||
|
} else if (strcmp(type, "FLOAT") == 0) {
|
||||||
|
return sql::data_type_t::type_float;
|
||||||
|
} else if (strcmp(type, "DOUBLE") == 0) {
|
||||||
|
return sql::data_type_t::type_double;
|
||||||
|
} else if (strcmp(type, "BLOB") == 0) {
|
||||||
|
return sql::data_type_t::type_blob;
|
||||||
|
} else if (strcmp(type, "NULL") == 0) {
|
||||||
|
return sql::data_type_t::type_null;
|
||||||
|
} else if (strncmp(type, "VARCHAR", 7) == 0) {
|
||||||
|
return sql::data_type_t::type_varchar;
|
||||||
|
} else if (strcmp(type, "DATE") == 0) {
|
||||||
|
return sql::data_type_t::type_date;
|
||||||
|
} else if (strcmp(type, "DATETIME") == 0) {
|
||||||
|
return sql::data_type_t::type_time;
|
||||||
|
} else if (strcmp(type, "TEXT") == 0) {
|
||||||
|
return sql::data_type_t::type_text;
|
||||||
|
} else {
|
||||||
|
return sql::data_type_t::type_unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::record sqlite_connection::describe(const std::string& table)
|
||||||
|
{
|
||||||
|
std::string stmt("PRAGMA table_info(" + table + ")");
|
||||||
|
const auto result = fetch("PRAGMA table_info(" + table + ")");
|
||||||
|
|
||||||
|
sql::record prototype;
|
||||||
|
while (result->fetch()) {
|
||||||
|
char *end = nullptr;
|
||||||
|
// Todo: add index to column
|
||||||
|
auto index = strtoul(result->column(0), &end, 10);
|
||||||
|
std::string name = result->column(1);
|
||||||
|
|
||||||
|
// Todo: extract size
|
||||||
|
auto type = (string2type(result->column(2)));
|
||||||
|
end = nullptr;
|
||||||
|
utils::constraints options{};
|
||||||
|
if (strtoul(result->column(3), &end, 10) == 0) {
|
||||||
|
options = utils::constraints::NOT_NULL;
|
||||||
|
}
|
||||||
|
// f.default_value(res->column(4));
|
||||||
|
// end = nullptr;
|
||||||
|
// f.is_primary_key(strtoul(res->column(3), &end, 10) == 0);
|
||||||
|
prototype.append({name, type, {options}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(prototype);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "sqlite_query_result.hpp"
|
#include "sqlite_query_result.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
@ -13,7 +14,7 @@ void read(Type &x, const char *val, typename std::enable_if<std::is_integral<Typ
|
||||||
}
|
}
|
||||||
char *end;
|
char *end;
|
||||||
x = static_cast<Type>(strtoll(val, &end, 10));
|
x = static_cast<Type>(strtoll(val, &end, 10));
|
||||||
if (end != nullptr) {
|
if (end == nullptr) {
|
||||||
// Todo: check error
|
// Todo: check error
|
||||||
throw std::logic_error("couldn't convert value to number");
|
throw std::logic_error("couldn't convert value to number");
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +28,7 @@ void read(Type &x, const char *val, typename std::enable_if<std::is_integral<Typ
|
||||||
}
|
}
|
||||||
char *end;
|
char *end;
|
||||||
x = static_cast<Type>(strtoull(val, &end, 10));
|
x = static_cast<Type>(strtoull(val, &end, 10));
|
||||||
if (end != nullptr) {
|
if (end == nullptr) {
|
||||||
// Todo: check error
|
// Todo: check error
|
||||||
throw std::logic_error("couldn't convert value to number");
|
throw std::logic_error("couldn't convert value to number");
|
||||||
}
|
}
|
||||||
|
|
@ -41,12 +42,21 @@ void read(Type &x, const char *val, typename std::enable_if<std::is_floating_poi
|
||||||
}
|
}
|
||||||
char *end;
|
char *end;
|
||||||
x = static_cast<Type>(strtold(val, &end));
|
x = static_cast<Type>(strtold(val, &end));
|
||||||
if (end != nullptr) {
|
if (end == nullptr) {
|
||||||
// Todo: check error
|
// Todo: check error
|
||||||
throw std::logic_error("couldn't convert value to number");
|
throw std::logic_error("couldn't convert value to number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite_query_result::~sqlite_query_result()
|
||||||
|
{
|
||||||
|
std::for_each(result_.begin(), result_.end(), [](rows ::value_type& row) {
|
||||||
|
std::for_each(row.begin(), row.end(), [](const char *val) {
|
||||||
|
delete [] val;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void sqlite_query_result::read_value(const char *id, size_t index, char &value)
|
void sqlite_query_result::read_value(const char *id, size_t index, char &value)
|
||||||
{
|
{
|
||||||
read(value, result_[row_index_][index]);
|
read(value, result_[row_index_][index]);
|
||||||
|
|
@ -162,10 +172,81 @@ void sqlite_query_result::push_back(char **row_values, int column_count)
|
||||||
result_.emplace_back(data);
|
result_.emplace_back(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sqlite_query_result::next_row()
|
const char* sqlite_query_result::column(size_t index) const
|
||||||
{
|
{
|
||||||
column_index_ = 0;
|
return result_[row_index_][index];
|
||||||
return row_index_++ < result_.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sqlite_query_result::fetch()
|
||||||
|
{
|
||||||
|
column_index_ = 0;
|
||||||
|
return ++row_index_ < result_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite_query_result::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case sql::data_type_t::type_char:
|
||||||
|
case sql::data_type_t::type_short:
|
||||||
|
case sql::data_type_t::type_int:
|
||||||
|
case sql::data_type_t::type_long:
|
||||||
|
case sql::data_type_t::type_long_long: {
|
||||||
|
long long val{};
|
||||||
|
read(val, result_[row_index_][index]);
|
||||||
|
value = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_unsigned_char:
|
||||||
|
case sql::data_type_t::type_unsigned_short:
|
||||||
|
case sql::data_type_t::type_unsigned_int:
|
||||||
|
case sql::data_type_t::type_unsigned_long:
|
||||||
|
case sql::data_type_t::type_unsigned_long_long: {
|
||||||
|
unsigned long long val{};
|
||||||
|
read(val, result_[row_index_][index]);
|
||||||
|
value = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_float:
|
||||||
|
case sql::data_type_t::type_double: {
|
||||||
|
double val{};
|
||||||
|
read(val, result_[row_index_][index]);
|
||||||
|
value = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_bool: {
|
||||||
|
int val{};
|
||||||
|
read(val, result_[row_index_][index]);
|
||||||
|
value = val > 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_text:
|
||||||
|
case sql::data_type_t::type_varchar: {
|
||||||
|
value = std::string{result_[row_index_][index]};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_char_pointer: {
|
||||||
|
value = result_[row_index_][index];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_time:
|
||||||
|
case sql::data_type_t::type_date: {
|
||||||
|
value = std::string{result_[row_index_][index]};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_null: {
|
||||||
|
value = nullptr_t{};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_blob: {
|
||||||
|
throw std::logic_error("data type blob not supported");
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_unknown: {
|
||||||
|
value = result_[row_index_][index];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +38,15 @@ public:
|
||||||
[[nodiscard]] const std::string& ref_column() const;
|
[[nodiscard]] const std::string& ref_column() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<class Operator>
|
||||||
|
void process(Operator &op)
|
||||||
|
{
|
||||||
|
op.on_attribute(name_.c_str(), value_, type_, attributes_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class record;
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
utils::field_attributes attributes_;
|
utils::field_attributes attributes_;
|
||||||
data_type_t type_{};
|
data_type_t type_{};
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,38 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace matador::utils {
|
|
||||||
class identifiable;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
class fk_column_generator : public utils::identifier_serializer
|
class fk_column_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
fk_column_generator() = default;
|
fk_column_generator() = default;
|
||||||
|
|
||||||
column generate(const char *id, utils::identifiable &x);
|
template<class Type>
|
||||||
|
column generate(const char *id, Type &x)
|
||||||
|
{
|
||||||
|
utils::access::process(*this, x);
|
||||||
|
return column{id, type_, { utils::constraints::FOREIGN_KEY }};
|
||||||
|
}
|
||||||
|
|
||||||
void serialize(short &i, const utils::field_attributes &attributes) override;
|
template<typename ValueType>
|
||||||
void serialize(int &i, const utils::field_attributes &attributes) override;
|
void on_primary_key(const char *, ValueType &/*pk*/, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
|
||||||
void serialize(long &i, const utils::field_attributes &attributes) override;
|
{
|
||||||
void serialize(long long int &i, const utils::field_attributes &attributes) override;
|
type_ = data_type_traits<ValueType>::builtin_type(0);
|
||||||
void serialize(unsigned short &i, const utils::field_attributes &attributes) override;
|
}
|
||||||
void serialize(unsigned int &i, const utils::field_attributes &attributes) override;
|
void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size);
|
||||||
void serialize(unsigned long &i, const utils::field_attributes &attributes) override;
|
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||||
void serialize(unsigned long long int &i, const utils::field_attributes &attributes) override;
|
template < class Type >
|
||||||
void serialize(std::string &string, const utils::field_attributes &attributes) override;
|
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||||
void serialize(utils::null_type_t &type, const utils::field_attributes &attributes) override;
|
void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_has_one(const char * /*id*/, Pointer &/*x*/, utils::cascade_type) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
data_type_t type_{};
|
data_type_t type_{};
|
||||||
|
|
@ -64,8 +73,16 @@ public:
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
|
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
|
||||||
|
|
||||||
void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type);
|
template<class Pointer>
|
||||||
void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type);
|
void on_belongs_to(const char *id, Pointer &x, utils::cascade_type)
|
||||||
|
{
|
||||||
|
columns_.push_back(fk_column_generator_.generate(id, *x));
|
||||||
|
}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_has_one(const char *id, Pointer &x, utils::cascade_type)
|
||||||
|
{
|
||||||
|
columns_.push_back(fk_column_generator_.generate(id, *x));
|
||||||
|
}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace matador::utils {
|
|
||||||
class identifiable;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
class column_name_generator
|
class column_name_generator
|
||||||
|
|
@ -45,8 +41,16 @@ public:
|
||||||
column_names_.emplace_back(id);
|
column_names_.emplace_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_belongs_to(const char *id, utils::identifiable &, utils::cascade_type);
|
template<class Pointer>
|
||||||
void on_has_one(const char *id, utils::identifiable &, utils::cascade_type);
|
void on_belongs_to(const char *id, Pointer &, utils::cascade_type)
|
||||||
|
{
|
||||||
|
column_names_.emplace_back(id);
|
||||||
|
}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_has_one(const char *id, Pointer &, utils::cascade_type)
|
||||||
|
{
|
||||||
|
column_names_.emplace_back(id);
|
||||||
|
}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "matador/sql/connection_info.hpp"
|
#include "matador/sql/connection_info.hpp"
|
||||||
#include "matador/sql/query_result_impl.hpp"
|
#include "matador/sql/query_result_impl.hpp"
|
||||||
|
#include "matador/sql/record.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -23,6 +24,8 @@ public:
|
||||||
virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0;
|
virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0;
|
||||||
virtual void prepare(const std::string &stmt) = 0;
|
virtual void prepare(const std::string &stmt) = 0;
|
||||||
|
|
||||||
|
virtual record describe(const std::string &table) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit connection_impl(const connection_info &info);
|
explicit connection_impl(const connection_info &info);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,18 @@
|
||||||
#ifndef QUERY_FOREIGN_HPP
|
#ifndef QUERY_FOREIGN_HPP
|
||||||
#define QUERY_FOREIGN_HPP
|
#define QUERY_FOREIGN_HPP
|
||||||
|
|
||||||
#include "matador/utils/identifiable.hpp"
|
#include <memory>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
template < class Type >
|
template < class Type >
|
||||||
class foreign : public utils::identifiable
|
class foreign
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
foreign() = default;
|
foreign() = default;
|
||||||
explicit foreign(Type *obj)
|
explicit foreign(Type *obj)
|
||||||
: obj_(obj) {}
|
: obj_(obj) {}
|
||||||
|
|
||||||
void reset(const utils::identifier &id) override {
|
|
||||||
id_ = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_primary_key() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] const utils::identifier &primary_key() const override {
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::identifier &primary_key() override {
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] utils::identifier create_identifier() const override {
|
|
||||||
return {id_};
|
|
||||||
}
|
|
||||||
|
|
||||||
Type* operator->() { return obj_.get(); }
|
Type* operator->() { return obj_.get(); }
|
||||||
const Type* operator->() const { return obj_.get(); }
|
const Type* operator->() const { return obj_.get(); }
|
||||||
|
|
||||||
|
|
@ -40,7 +20,6 @@ public:
|
||||||
const Type& operator*() const { return *obj_; }
|
const Type& operator*() const { return *obj_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utils::identifier id_;
|
|
||||||
std::unique_ptr<Type> obj_;
|
std::unique_ptr<Type> obj_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,6 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace matador::utils {
|
|
||||||
class identifiable;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
class key_value_generator
|
class key_value_generator
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,14 @@
|
||||||
#include "matador/sql/basic_condition.hpp"
|
#include "matador/sql/basic_condition.hpp"
|
||||||
#include "matador/sql/column.hpp"
|
#include "matador/sql/column.hpp"
|
||||||
#include "matador/sql/key_value_pair.hpp"
|
#include "matador/sql/key_value_pair.hpp"
|
||||||
|
#include "matador/sql/record.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
class dialect;
|
class dialect;
|
||||||
|
|
@ -121,6 +123,8 @@ public:
|
||||||
|
|
||||||
std::string compile();
|
std::string compile();
|
||||||
|
|
||||||
|
[[nodiscard]] const record& prototype() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void transition_to(state_t next);
|
void transition_to(state_t next);
|
||||||
void initialize(command_t cmd, state_t state);
|
void initialize(command_t cmd, state_t state);
|
||||||
|
|
@ -135,6 +139,8 @@ private:
|
||||||
|
|
||||||
detail::any_type_to_string_visitor value_to_string_;
|
detail::any_type_to_string_visitor value_to_string_;
|
||||||
|
|
||||||
|
record prototype_;
|
||||||
|
|
||||||
using query_state_set = std::unordered_set<state_t>;
|
using query_state_set = std::unordered_set<state_t>;
|
||||||
using query_state_transition_map = std::unordered_map<state_t, query_state_set>;
|
using query_state_transition_map = std::unordered_map<state_t, query_state_set>;
|
||||||
using query_state_to_string_map = std::unordered_map<state_t, std::string>;
|
using query_state_to_string_map = std::unordered_map<state_t, std::string>;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef QUERY_QUERY_RESULT_HPP
|
#ifndef QUERY_QUERY_RESULT_HPP
|
||||||
#define QUERY_QUERY_RESULT_HPP
|
#define QUERY_QUERY_RESULT_HPP
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "matador/sql/query_result_impl.hpp"
|
#include "matador/sql/query_result_impl.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -23,10 +25,10 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
query_result_iterator() = default;
|
query_result_iterator() = default;
|
||||||
explicit query_result_iterator(query_result<Type> &res)
|
explicit query_result_iterator(query_result<Type> *res)
|
||||||
: result_(res)
|
: result_(res)
|
||||||
{}
|
{}
|
||||||
query_result_iterator(query_result<Type> &res, std::unique_ptr<Type> obj)
|
query_result_iterator(query_result<Type> *res, std::unique_ptr<Type> obj)
|
||||||
: obj_(std::move(obj))
|
: obj_(std::move(obj))
|
||||||
, result_(res)
|
, result_(res)
|
||||||
{}
|
{}
|
||||||
|
|
@ -56,9 +58,9 @@ public:
|
||||||
|
|
||||||
self& operator++()
|
self& operator++()
|
||||||
{
|
{
|
||||||
obj_.reset(result_.create());
|
obj_.reset(result_->create());
|
||||||
result_.bind(*obj_);
|
result_->bind(*obj_);
|
||||||
if (!result_.fetch(*obj_)) {
|
if (!result_->fetch(*obj_)) {
|
||||||
obj_.reset();
|
obj_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +71,9 @@ public:
|
||||||
{
|
{
|
||||||
const self tmp(result_, obj_);
|
const self tmp(result_, obj_);
|
||||||
|
|
||||||
obj_.reset(result_.create());
|
obj_.reset(result_->create());
|
||||||
result_.bind(*obj_);
|
result_->bind(*obj_);
|
||||||
if (!result_.fetch(*obj_)) {
|
if (!result_->fetch(*obj_)) {
|
||||||
obj_.reset();
|
obj_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +102,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Type> obj_;
|
std::unique_ptr<Type> obj_;
|
||||||
query_result<Type> &result_;
|
query_result<Type> *result_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
|
|
@ -108,18 +110,22 @@ class query_result
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using iterator = query_result_iterator<Type>;
|
using iterator = query_result_iterator<Type>;
|
||||||
|
using creator_func = std::function<Type*()>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit query_result(std::unique_ptr<query_result_impl> impl)
|
explicit query_result(std::unique_ptr<query_result_impl> impl)
|
||||||
: impl_(std::move(impl)) {}
|
: impl_(std::move(impl)) {}
|
||||||
|
query_result(std::unique_ptr<query_result_impl> impl, creator_func creator)
|
||||||
|
: creator_(creator)
|
||||||
|
, impl_(std::move(impl)) {}
|
||||||
|
|
||||||
iterator begin() { return std::move(++iterator(*this)); }
|
iterator begin() { return std::move(++iterator(this)); }
|
||||||
iterator end() { return {}; }
|
iterator end() { return {}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class query_result_iterator<Type>;
|
friend class query_result_iterator<Type>;
|
||||||
|
|
||||||
Type* create() { return new Type; }
|
Type* create() { return creator_(); }
|
||||||
|
|
||||||
void bind(const Type &obj)
|
void bind(const Type &obj)
|
||||||
{
|
{
|
||||||
|
|
@ -132,6 +138,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
creator_func creator_ = []{ return new Type; };
|
||||||
std::unique_ptr<query_result_impl> impl_;
|
std::unique_ptr<query_result_impl> impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
#include "matador/utils/field_attributes.hpp"
|
#include "matador/utils/field_attributes.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include "matador/sql/any_type.hpp"
|
||||||
|
#include "matador/sql/types.hpp"
|
||||||
|
|
||||||
namespace matador::utils {
|
#include <string>
|
||||||
class identifiable;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
|
@ -35,6 +34,7 @@ public:
|
||||||
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
|
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
|
||||||
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
|
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
|
||||||
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
|
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
|
||||||
|
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size) = 0;
|
||||||
|
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
|
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
|
||||||
|
|
@ -51,9 +51,12 @@ public:
|
||||||
}
|
}
|
||||||
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
|
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
|
||||||
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
|
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
|
||||||
|
void on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr = utils::null_attributes);
|
||||||
|
|
||||||
void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type);
|
template < class Pointer >
|
||||||
void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type);
|
void on_belongs_to(const char *id, Pointer &x, utils::cascade_type) {}
|
||||||
|
template < class Pointer >
|
||||||
|
void on_has_one(const char *id, Pointer &x, utils::cascade_type) {}
|
||||||
|
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
|
||||||
|
|
@ -66,15 +69,15 @@ public:
|
||||||
template<class Type>
|
template<class Type>
|
||||||
bool fetch(Type &obj)
|
bool fetch(Type &obj)
|
||||||
{
|
{
|
||||||
if (!next_row()) {
|
if (!fetch()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
matador::utils::access::process(*this, obj);
|
matador::utils::access::process(*this, obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
[[nodiscard]] virtual const char* column(size_t index) const = 0;
|
||||||
[[nodiscard]] virtual bool next_row() = 0;
|
[[nodiscard]] virtual bool fetch() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t column_index_ = 0;
|
size_t column_index_ = 0;
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,17 @@ public:
|
||||||
|
|
||||||
record() = default;
|
record() = default;
|
||||||
record(std::initializer_list<column> columns);
|
record(std::initializer_list<column> columns);
|
||||||
|
record(const record&) = default;
|
||||||
|
record& operator=(const record&) = default;
|
||||||
|
record(record&&) noexcept = default;
|
||||||
|
record& operator=(record&&) noexcept = default;
|
||||||
~record() = default;
|
~record() = default;
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op)
|
void process(Operator &op)
|
||||||
{
|
{
|
||||||
for(auto &col : columns_) {
|
for(auto &col : columns_) {
|
||||||
// Todo: Find a solution to handle a column with process
|
col.process(op);
|
||||||
int todo{};
|
|
||||||
matador::utils::access::attribute(op, col.name().c_str(), todo, col.attributes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
|
|
@ -43,10 +45,10 @@ public:
|
||||||
void append(column col);
|
void append(column col);
|
||||||
|
|
||||||
[[nodiscard]] const column& at(const std::string &name) const;
|
[[nodiscard]] const column& at(const std::string &name) const;
|
||||||
const column& at(size_t index);
|
const column& at(size_t index) const;
|
||||||
|
|
||||||
iterator find(const std::string &column_name);
|
iterator find(const std::string &column_name);
|
||||||
const_iterator find(const std::string &column_name) const;
|
[[nodiscard]] const_iterator find(const std::string &column_name) const;
|
||||||
|
|
||||||
iterator begin();
|
iterator begin();
|
||||||
[[nodiscard]] const_iterator begin() const;
|
[[nodiscard]] const_iterator begin() const;
|
||||||
|
|
@ -57,6 +59,8 @@ public:
|
||||||
[[nodiscard]] const_iterator cend() const;
|
[[nodiscard]] const_iterator cend() const;
|
||||||
|
|
||||||
[[nodiscard]] size_t size() const;
|
[[nodiscard]] size_t size() const;
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
column_by_index columns_;
|
column_by_index columns_;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ inline constraints operator&(constraints a, constraints b)
|
||||||
return static_cast<constraints>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
|
return static_cast<constraints>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline constraints& operator|= (constraints& a, constraints b) { return (constraints&)((int&)a |= (int)b); }
|
||||||
|
inline constraints& operator&= (constraints& a, constraints b) { return (constraints&)((int&)a &= (int)b); }
|
||||||
|
|
||||||
inline bool is_constraint_set(constraints source, constraints needle)
|
inline bool is_constraint_set(constraints source, constraints needle)
|
||||||
{
|
{
|
||||||
return static_cast<int>(source & needle) > 0;
|
return static_cast<int>(source & needle) > 0;
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
#ifndef QUERY_IDENTIFIABLE_HPP
|
|
||||||
#define QUERY_IDENTIFIABLE_HPP
|
|
||||||
|
|
||||||
#include "matador/utils/identifier.hpp"
|
|
||||||
|
|
||||||
namespace matador::utils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for all pointer object
|
|
||||||
* which can contain an identifiable
|
|
||||||
*/
|
|
||||||
class identifiable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~identifiable() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the object_holder with the given
|
|
||||||
* identifier. If the type of identifier differs
|
|
||||||
* from internal type an exception is thrown
|
|
||||||
*
|
|
||||||
* @param id The identifier to set
|
|
||||||
*/
|
|
||||||
virtual void reset(const identifier &id) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if serializable has a primary key
|
|
||||||
*
|
|
||||||
* @return true if serializable has a primary key
|
|
||||||
*/
|
|
||||||
[[nodiscard]] virtual bool has_primary_key() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the primary key of the foreign serializable
|
|
||||||
*
|
|
||||||
* @return The primary key of the foreign serializable
|
|
||||||
*/
|
|
||||||
[[nodiscard]] virtual const identifier& primary_key() const = 0;
|
|
||||||
virtual identifier& primary_key() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new identifier object.
|
|
||||||
*
|
|
||||||
* @return Returns a new identifier object.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] virtual identifier create_identifier() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_IDENTIFIABLE_HPP
|
|
||||||
|
|
@ -51,7 +51,6 @@ set(UTILS_HEADER
|
||||||
../include/matador/utils/library.hpp
|
../include/matador/utils/library.hpp
|
||||||
../include/matador/utils/os.hpp
|
../include/matador/utils/os.hpp
|
||||||
../include/matador/utils/access.hpp
|
../include/matador/utils/access.hpp
|
||||||
../include/matador/utils/identifiable.hpp
|
|
||||||
../include/matador/utils/identifier.hpp
|
../include/matador/utils/identifier.hpp
|
||||||
../include/matador/utils/cascade_type.hpp)
|
../include/matador/utils/cascade_type.hpp)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
#include "matador/sql/column_generator.hpp"
|
#include "matador/sql/column_generator.hpp"
|
||||||
|
|
||||||
#include "matador/utils/identifiable.hpp"
|
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
column_generator::column_generator(std::vector<column> &columns)
|
column_generator::column_generator(std::vector<column> &columns)
|
||||||
|
|
@ -17,80 +15,9 @@ void column_generator::on_revision(const char *id, unsigned long long int &x)
|
||||||
on_attribute(id, x);
|
on_attribute(id, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void column_generator::on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type)
|
void fk_column_generator::on_primary_key(const char *, std::string &, size_t size)
|
||||||
{
|
{
|
||||||
columns_.push_back(fk_column_generator_.generate(id, x));
|
type_ = data_type_traits<std::string>::builtin_type(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void column_generator::on_has_one(const char *id, utils::identifiable &x, utils::cascade_type)
|
|
||||||
{
|
|
||||||
columns_.push_back(fk_column_generator_.generate(id, x));
|
|
||||||
}
|
|
||||||
|
|
||||||
column fk_column_generator::generate(const char *id, utils::identifiable &x)
|
|
||||||
{
|
|
||||||
x.primary_key().serialize(*this);
|
|
||||||
return column{id, type_, { utils::constraints::FOREIGN_KEY }};
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
data_type_t determine_data_type(const Type &)
|
|
||||||
{
|
|
||||||
return data_type_traits<Type>::builtin_type(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
data_type_t determine_data_type(const std::string&, size_t size)
|
|
||||||
{
|
|
||||||
return data_type_traits<std::string>::builtin_type(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(short &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(int &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(long &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(long long int &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(unsigned short &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(unsigned int &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(unsigned long &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(unsigned long long int &i, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(std::string &x, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = determine_data_type(x, attributes.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void fk_column_generator::serialize(utils::null_type_t &type, const utils::field_attributes &attributes)
|
|
||||||
{
|
|
||||||
type_ = data_type_t::type_null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,14 +16,4 @@ void column_name_generator::on_revision(const char *id, unsigned long long int &
|
||||||
column_names_.emplace_back(id);
|
column_names_.emplace_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void column_name_generator::on_belongs_to(const char *id, utils::identifiable &, utils::cascade_type)
|
|
||||||
{
|
|
||||||
column_names_.emplace_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void column_name_generator::on_has_one(const char *id, utils::identifiable &, utils::cascade_type)
|
|
||||||
{
|
|
||||||
column_names_.emplace_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +65,8 @@ const connection_info &connection::info() const
|
||||||
|
|
||||||
query_result<record> connection::fetch(const std::string &sql)
|
query_result<record> connection::fetch(const std::string &sql)
|
||||||
{
|
{
|
||||||
return query_result<record>(connection_->fetch(sql));
|
auto rec = connection_->describe("person");
|
||||||
|
return {connection_->fetch(sql), [rec](){ return new record(rec); }};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<size_t, std::string> connection::execute(const std::string &sql)
|
std::pair<size_t, std::string> connection::execute(const std::string &sql)
|
||||||
|
|
|
||||||
|
|
@ -97,27 +97,32 @@ query_builder& query_builder::drop() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_builder& query_builder::select(std::initializer_list<std::string> column_names) {
|
query_builder& query_builder::select(std::initializer_list<std::string> column_names)
|
||||||
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
{
|
||||||
|
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
||||||
|
|
||||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::SELECT) + " ");
|
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::SELECT) + " ");
|
||||||
|
|
||||||
std::string result;
|
prototype_.clear();
|
||||||
if (column_names.size() < 2) {
|
|
||||||
for (const auto &col : column_names) {
|
std::string result;
|
||||||
result.append(dialect_.prepare_identifier(col));
|
if (column_names.size() < 2) {
|
||||||
}
|
for (const auto &col : column_names) {
|
||||||
} else {
|
result.append(dialect_.prepare_identifier(col));
|
||||||
auto it = column_names.begin();
|
prototype_.append(column{col});
|
||||||
result.append(dialect_.prepare_identifier(*it++));
|
|
||||||
for (; it != column_names.end(); ++it) {
|
|
||||||
result.append(", ");
|
|
||||||
result.append(dialect_.prepare_identifier(*it));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
auto it = column_names.begin();
|
||||||
|
result.append(dialect_.prepare_identifier(*it++));
|
||||||
|
for (; it != column_names.end(); ++it) {
|
||||||
|
result.append(", ");
|
||||||
|
result.append(dialect_.prepare_identifier(*it));
|
||||||
|
prototype_.append(column{*it});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
query_parts_.emplace_back(result);
|
query_parts_.emplace_back(result);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_builder& query_builder::insert() {
|
query_builder& query_builder::insert() {
|
||||||
|
|
@ -393,6 +398,11 @@ std::string query_builder::compile() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const record& query_builder::prototype() const
|
||||||
|
{
|
||||||
|
return prototype_;
|
||||||
|
}
|
||||||
|
|
||||||
void query_builder::transition_to(query_builder::state_t next)
|
void query_builder::transition_to(query_builder::state_t next)
|
||||||
{
|
{
|
||||||
if (transitions_[state_].count(next) == 0) {
|
if (transitions_[state_].count(next) == 0) {
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,10 @@ void query_result_impl::on_attribute(const char *id, std::string &value, const u
|
||||||
read_value(id, column_index_++, value, attr.size());
|
read_value(id, column_index_++, value, attr.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void query_result_impl::on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type)
|
void
|
||||||
|
query_result_impl::on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr)
|
||||||
{
|
{
|
||||||
|
read_value(id, column_index_++, value, type, attr.size());
|
||||||
}
|
|
||||||
|
|
||||||
void query_result_impl::on_has_one(const char *id, utils::identifiable &x, utils::cascade_type)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ const column &record::at(const std::string &name) const
|
||||||
return columns_by_name_.at(name).first;
|
return columns_by_name_.at(name).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
const column &record::at(size_t index)
|
const column &record::at(size_t index) const
|
||||||
{
|
{
|
||||||
return columns_.at(index);
|
return columns_.at(index);
|
||||||
}
|
}
|
||||||
|
|
@ -72,4 +72,15 @@ size_t record::size() const
|
||||||
return columns_.size();
|
return columns_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
bool record::empty() const
|
||||||
|
{
|
||||||
|
return columns_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void record::clear()
|
||||||
|
{
|
||||||
|
columns_.clear();
|
||||||
|
columns_by_name_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador::test;
|
using namespace matador::test;
|
||||||
|
|
||||||
TEST_CASE("Execute create table statement", "[session]") {
|
TEST_CASE("Execute create and drop table statement", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
||||||
|
|
@ -22,30 +22,81 @@ TEST_CASE("Execute create table statement", "[session]") {
|
||||||
|
|
||||||
REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255), "age" INTEGER, CONSTRAINT PK_person PRIMARY KEY (id)))");
|
REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255), "age" INTEGER, CONSTRAINT PK_person PRIMARY KEY (id)))");
|
||||||
|
|
||||||
REQUIRE(s.drop().table("person").execute().first == 0);
|
res = s.drop().table("person").execute();
|
||||||
// REQUIRE(res.first == 1);
|
|
||||||
|
|
||||||
// res = s.create().table<product>("product").execute();
|
REQUIRE(res.second == R"(DROP TABLE "person")");
|
||||||
|
|
||||||
// REQUIRE(res.second == R"(CREATE TABLE "product" ("product_name" VARCHAR(255) PRIMARY KEY, "supplier_id" BIGINT NOT NULL FOREIGN KEY, "category_id" BIGINT NOT NULL FOREIGN KEY, "quantity_per_unit" VARCHAR(255), "unit_price" BIGINT, "units_in_stock" BIGINT, "units_in_order" BIGINT, "reorder_level" BIGINT, "discontinued" BOOLEAN))");
|
|
||||||
|
|
||||||
// res = s.drop().table("person").execute();
|
|
||||||
// REQUIRE(res.first == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute create table statement with foreign keys", "[session]") {
|
TEST_CASE("Execute create table statement with foreign keys", "[session]") {
|
||||||
|
// res = s.create().table<product>("product").execute();
|
||||||
|
|
||||||
|
// REQUIRE(res.second == R"(CREATE TABLE "product" ("product_name" VARCHAR(255) PRIMARY KEY, "supplier_id" BIGINT NOT NULL FOREIGN KEY, "category_id" BIGINT NOT NULL FOREIGN KEY, "quantity_per_unit" VARCHAR(255), "unit_price" BIGINT, "units_in_stock" BIGINT, "units_in_order" BIGINT, "reorder_level" BIGINT, "discontinued" BOOLEAN))");
|
||||||
|
|
||||||
|
// res = s.drop().table("person").execute();
|
||||||
|
// REQUIRE(res.first == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute drop table statement", "[session]") {
|
TEST_CASE("Execute insert record statement", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
||||||
const auto res = s.drop()
|
auto res = s
|
||||||
.table("person")
|
.create()
|
||||||
.execute();
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
REQUIRE(res.second == R"(DROP TABLE "person")");
|
REQUIRE(res.first == 0);
|
||||||
|
|
||||||
|
res = s
|
||||||
|
.insert()
|
||||||
|
.into("person", {"id", "name", "age"})
|
||||||
|
.values({7, "george", 45})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
REQUIRE(res.second == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 45))");
|
||||||
|
|
||||||
|
auto result = s
|
||||||
|
.select({"id", "name", "age"})
|
||||||
|
.from("person")
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
for (const auto& i : result) {
|
||||||
|
REQUIRE(i.size() == 3);
|
||||||
|
REQUIRE(i.at(0).name() == "id");
|
||||||
|
REQUIRE(i.at(0).type() == data_type_t::type_long_long);
|
||||||
|
REQUIRE(i.at(1).name() == "name");
|
||||||
|
REQUIRE(i.at(1).type() == data_type_t::type_varchar);
|
||||||
|
REQUIRE(i.at(2).name() == "age");
|
||||||
|
REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int);
|
||||||
|
}
|
||||||
|
s.drop().table("person").execute();
|
||||||
|
|
||||||
|
// using namespace matador::test;
|
||||||
|
// product p;
|
||||||
|
// p.discontinued = false;
|
||||||
|
// p.reorder_level = 1;
|
||||||
|
// p.units_in_order = 2;
|
||||||
|
// p.units_in_stock = 100;
|
||||||
|
// p.unit_price = 49;
|
||||||
|
// p.quantity_per_unit = "pcs";
|
||||||
|
// p.category = make_foreign<matador::test::category>();
|
||||||
|
// p.category->id = 7;
|
||||||
|
// p.supplier = make_foreign<matador::test::supplier>();;
|
||||||
|
// p.supplier->id = 13;
|
||||||
|
// p.product_name = "candle";
|
||||||
|
//
|
||||||
|
// res = s.insert().into<product>("product").values(p).execute();
|
||||||
|
//
|
||||||
|
// REQUIRE(res.second == R"(INSERT INTO "product" ("product_name", "supplier_id", "category_id", "quantity_per_unit", "unit_price", "units_in_stock", "units_in_order", "reorder_level", "discontinued") VALUES ('candle', 13, 7, 'pcs', 49, 100, 2, 1, 0))");
|
||||||
|
//
|
||||||
|
// res = s.insert().into("product", p).execute();
|
||||||
|
//
|
||||||
|
// REQUIRE(res.second == R"(INSERT INTO "product" ("product_name", "supplier_id", "category_id", "quantity_per_unit", "unit_price", "units_in_stock", "units_in_order", "reorder_level", "discontinued") VALUES ('candle', 13, 7, 'pcs', 49, 100, 2, 1, 0))");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with where clause", "[session]") {
|
TEST_CASE("Execute select statement with where clause", "[session]") {
|
||||||
|
|
@ -114,7 +165,7 @@ TEST_CASE("Execute insert statement", "[session]") {
|
||||||
p.quantity_per_unit = "pcs";
|
p.quantity_per_unit = "pcs";
|
||||||
p.category = make_foreign<matador::test::category>();
|
p.category = make_foreign<matador::test::category>();
|
||||||
p.category->id = 7;
|
p.category->id = 7;
|
||||||
p.supplier = make_foreign<matador::test::supplier>();;
|
p.supplier = make_foreign<matador::test::supplier>();
|
||||||
p.supplier->id = 13;
|
p.supplier->id = 13;
|
||||||
p.product_name = "candle";
|
p.product_name = "candle";
|
||||||
|
|
||||||
|
|
@ -151,7 +202,7 @@ TEST_CASE("Execute update statement", "[session]") {
|
||||||
p.quantity_per_unit = "pcs";
|
p.quantity_per_unit = "pcs";
|
||||||
p.category = make_foreign<matador::test::category>();
|
p.category = make_foreign<matador::test::category>();
|
||||||
p.category->id = 7;
|
p.category->id = 7;
|
||||||
p.supplier = make_foreign<matador::test::supplier>();;
|
p.supplier = make_foreign<matador::test::supplier>();
|
||||||
p.supplier->id = 13;
|
p.supplier->id = 13;
|
||||||
p.product_name = "candle";
|
p.product_name = "candle";
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue