Compare commits
19
Commits
fa7ff832c9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19de5714f4 | ||
|
|
484c2d8b05 | ||
|
|
43d2f81b95 | ||
|
|
27f6c81da2 | ||
|
|
12e5b27a8c | ||
|
|
ff3a2e4217 | ||
|
|
ac8b2ed4e4 | ||
|
|
38da76bfb3 | ||
|
|
4199c5029c | ||
|
|
fb57545cce | ||
|
|
7bb7afa227 | ||
|
|
2022f6f75b | ||
|
|
b4765cac88 | ||
|
|
25bcc362f2 | ||
|
|
b7c12d8217 | ||
|
|
1fe5c9bac4 | ||
|
|
8f754f3542 | ||
|
|
f977b2afc9 | ||
|
|
5a3cdc8645 |
@@ -1,3 +1,4 @@
|
|||||||
.idea
|
.idea
|
||||||
cmake-build-debug
|
cmake-build-debug
|
||||||
Testing
|
Testing
|
||||||
|
debug
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ find_package(SQLite3 REQUIRED)
|
|||||||
find_package(PostgreSQL REQUIRED)
|
find_package(PostgreSQL REQUIRED)
|
||||||
find_package(MySQL REQUIRED)
|
find_package(MySQL REQUIRED)
|
||||||
|
|
||||||
|
message(STATUS "Found ODBC config ${ODBC_CONFIG}")
|
||||||
|
message(STATUS "Adding ODBC include directory: ${ODBC_INCLUDE_DIRS}")
|
||||||
|
message(STATUS "Adding ODBC libs: ${ODBC_LIBRARIES}")
|
||||||
|
|
||||||
message(STATUS "Found SQLite3 ${SQLite3_VERSION}")
|
message(STATUS "Found SQLite3 ${SQLite3_VERSION}")
|
||||||
message(STATUS "Adding SQLite3 include directory: ${SQLite3_INCLUDE_DIRS}")
|
message(STATUS "Adding SQLite3 include directory: ${SQLite3_INCLUDE_DIRS}")
|
||||||
message(STATUS "Adding SQLite3 libs: ${SQLite3_LIBRARIES}")
|
message(STATUS "Adding SQLite3 libs: ${SQLite3_LIBRARIES}")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.4.0 # or a later release
|
GIT_TAG v3.5.4 # or a later release
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.4.0 # or a later release
|
GIT_TAG v3.5.4 # or a later release
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
void read_value(const char *id, size_t index, char *value, size_t s) override;
|
void read_value(const char *id, size_t index, char *value, size_t s) 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;
|
void read_value(const char *id, size_t index, sql::value &val, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sqlite3 *db_{nullptr};
|
sqlite3 *db_{nullptr};
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ void sqlite_prepared_result_reader::read_value(const char *id, size_t index, std
|
|||||||
query_result_reader::read_value(id, index, value, s);
|
query_result_reader::read_value(id, index, value, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sqlite_prepared_result_reader::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size)
|
void sqlite_prepared_result_reader::read_value(const char *id, size_t index, sql::value &val, size_t size)
|
||||||
{
|
{
|
||||||
query_result_reader::read_value(id, index, value, type, size);
|
query_result_reader::read_value(id, index, val, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ Include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.4.0 # or a later release
|
GIT_TAG v3.5.4 # or a later release
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
|
|||||||
|
|
||||||
auto expected_flight = flights[0];
|
auto expected_flight = flights[0];
|
||||||
|
|
||||||
REQUIRE(result.has_value());
|
REQUIRE(result);
|
||||||
REQUIRE(result->id == expected_flight->id);
|
REQUIRE(result->id == expected_flight->id);
|
||||||
REQUIRE(result->pilot_name == expected_flight->pilot_name);
|
REQUIRE(result->pilot_name == expected_flight->pilot_name);
|
||||||
REQUIRE(result->airplane.get());
|
REQUIRE(result->airplane.get());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "matador/sql/session.hpp"
|
#include "matador/sql/session.hpp"
|
||||||
|
|
||||||
#include "models/airplane.hpp"
|
#include "models/airplane.hpp"
|
||||||
|
#include "models/flight.hpp"
|
||||||
|
|
||||||
class SessionFixture
|
class SessionFixture
|
||||||
{
|
{
|
||||||
@@ -16,9 +17,8 @@ public:
|
|||||||
|
|
||||||
~SessionFixture()
|
~SessionFixture()
|
||||||
{
|
{
|
||||||
drop_table_if_exists("flight");
|
drop_table_if_exists("flights");
|
||||||
drop_table_if_exists("airplane");
|
drop_table_if_exists("airplanes");
|
||||||
drop_table_if_exists("person");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -38,19 +38,62 @@ using namespace matador;
|
|||||||
|
|
||||||
TEST_CASE_METHOD(SessionFixture, "Session relation test", "[session][relation]") {
|
TEST_CASE_METHOD(SessionFixture, "Session relation test", "[session][relation]") {
|
||||||
using namespace matador;
|
using namespace matador;
|
||||||
ses.attach<test::airplane>("airplane");
|
ses.attach<test::airplane>("airplanes");
|
||||||
|
ses.attach<test::flight>("flights");
|
||||||
ses.create_schema();
|
ses.create_schema();
|
||||||
ses.insert<test::airplane>(1, "Boeing", "A380");
|
auto plane = ses.insert<test::airplane>(1, "Boeing", "A380");
|
||||||
|
auto f = ses.insert<test::flight>(2, plane, "sully");
|
||||||
|
|
||||||
REQUIRE(true);
|
auto result = ses.find<test::flight>(2);
|
||||||
|
REQUIRE(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(SessionFixture, "Find object with id", "[session][find]") {
|
TEST_CASE_METHOD(SessionFixture, "Use session to find object with id", "[session][find]") {
|
||||||
using namespace matador::test;
|
using namespace matador::test;
|
||||||
ses.attach<airplane>("airplane");
|
ses.attach<airplane>("airplanes");
|
||||||
ses.create_schema();
|
ses.create_schema();
|
||||||
auto a380 = ses.insert<airplane>(1, "Boeing", "A380");
|
auto a380 = ses.insert<airplane>(1, "Boeing", "A380");
|
||||||
|
|
||||||
ses.find<airplane>(1);
|
auto result = ses.find<airplane>(2);
|
||||||
|
REQUIRE(!result.is_ok());
|
||||||
|
REQUIRE((result.err() == sql::session_error::FailedToFindObject));
|
||||||
|
|
||||||
|
result = ses.find<airplane>(1);
|
||||||
|
|
||||||
|
REQUIRE(result);
|
||||||
|
auto read_a380 = result.value();
|
||||||
|
REQUIRE(a380->id == read_a380->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(SessionFixture, "Use session to find all objects", "[session][find]") {
|
||||||
|
using namespace matador::test;
|
||||||
|
ses.attach<airplane>("airplanes");
|
||||||
|
ses.create_schema();
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<airplane>> planes;
|
||||||
|
planes.emplace_back(new airplane(1, "Airbus", "A380"));
|
||||||
|
planes.emplace_back(new airplane(2, "Boeing", "707"));
|
||||||
|
planes.emplace_back(new airplane(3, "Boeing", "747"));
|
||||||
|
|
||||||
|
for (auto &&plane: planes) {
|
||||||
|
ses.insert(plane.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = ses.find<airplane>();
|
||||||
|
|
||||||
|
std::vector<std::tuple<int, std::string, std::string>> expected_result {
|
||||||
|
{1, "Airbus", "A380"},
|
||||||
|
{2, "Boeing", "707"},
|
||||||
|
{3, "Boeing", "747"}
|
||||||
|
};
|
||||||
|
REQUIRE(result);
|
||||||
|
auto all_planes = result.release();
|
||||||
|
size_t index {0};
|
||||||
|
for (const auto &i: all_planes) {
|
||||||
|
REQUIRE(i.id == std::get<0>(expected_result[index]));
|
||||||
|
REQUIRE(i.brand == std::get<1>(expected_result[index]));
|
||||||
|
REQUIRE(i.model == std::get<2>(expected_result[index]));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -52,38 +52,32 @@ static const matador::utils::enum_mapper<Color> color_enum({
|
|||||||
{Color::Brown, "brown"}
|
{Color::Brown, "brown"}
|
||||||
});
|
});
|
||||||
|
|
||||||
namespace matador::sql {
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct data_type_traits<Color, void>
|
struct matador::sql::data_type_traits<Color, void>
|
||||||
{
|
{
|
||||||
inline static data_type_t builtin_type(std::size_t size)
|
inline static data_type_t builtin_type(std::size_t size)
|
||||||
{ return data_type_traits<std::string>::builtin_type(size); }
|
{ return data_type_traits<std::string>::builtin_type(size); }
|
||||||
|
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, Color &value)
|
static void read_value(query_result_reader &reader, const char *id, size_t index, Color &value)
|
||||||
{
|
{
|
||||||
std::string enum_string;
|
std::string enum_string;
|
||||||
reader.read_value(id, index, enum_string, 64);
|
reader.read_value(id, index, enum_string, 64);
|
||||||
auto enum_opt = color_enum.to_enum(enum_string);
|
if (const auto enum_opt = color_enum.to_enum(enum_string)) {
|
||||||
if (enum_opt) {
|
value = enum_opt.value();
|
||||||
value = enum_opt.value();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static any_type create_value(Color &value)
|
static any_type create_value(const Color &value)
|
||||||
{
|
{
|
||||||
return color_enum.to_string(value);
|
return color_enum.to_string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bind_value(parameter_binder &binder, size_t index, Color &value)
|
static void bind_value(parameter_binder &binder, size_t index, Color &value)
|
||||||
{
|
{
|
||||||
binder.bind(index, color_enum.to_string(value));
|
binder.bind(index, color_enum.to_string(value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with type traits", "[typetraits]")
|
TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with type traits", "[typetraits]")
|
||||||
{
|
{
|
||||||
schema.attach<location>("location");
|
schema.attach<location>("location");
|
||||||
|
|||||||
+251
-126
@@ -5,166 +5,291 @@
|
|||||||
#include "matador/sql/entity.hpp"
|
#include "matador/sql/entity.hpp"
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
|
#include "matador/utils/enum_mapper.hpp"
|
||||||
|
|
||||||
#include "matador/sql/query_helper.hpp"
|
#include "matador/sql/query_helper.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct author
|
struct author {
|
||||||
{
|
unsigned long id{};
|
||||||
unsigned long id{};
|
std::string first_name;
|
||||||
std::string first_name;
|
std::string last_name;
|
||||||
std::string last_name;
|
std::string date_of_birth;
|
||||||
std::string date_of_birth;
|
unsigned short year_of_birth{};
|
||||||
unsigned short year_of_birth{};
|
bool distinguished{false};
|
||||||
bool distinguished{false};
|
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op)
|
void process( Operator& op ) {
|
||||||
{
|
namespace field = matador::utils::access;
|
||||||
namespace field = matador::utils::access;
|
field::primary_key( op, "id", id );
|
||||||
field::primary_key(op, "id", id);
|
field::attribute( op, "first_name", first_name, 63 );
|
||||||
field::attribute(op, "first_name", first_name, 63);
|
field::attribute( op, "last_name", last_name, 63 );
|
||||||
field::attribute(op, "last_name", last_name, 63);
|
field::attribute( op, "date_of_birth", date_of_birth, 31 );
|
||||||
field::attribute(op, "date_of_birth", date_of_birth, 31);
|
field::attribute( op, "year_of_birth", year_of_birth );
|
||||||
field::attribute(op, "year_of_birth", year_of_birth);
|
field::attribute( op, "distinguished", distinguished );
|
||||||
field::attribute(op, "distinguished", distinguished);
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct book
|
struct book {
|
||||||
{
|
unsigned long id{};
|
||||||
unsigned long id{};
|
matador::sql::entity<author> book_author;
|
||||||
matador::sql::entity<author> book_author;
|
std::string title;
|
||||||
std::string title;
|
unsigned short published_in{};
|
||||||
unsigned short published_in{};
|
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op)
|
void process( Operator& op ) {
|
||||||
{
|
namespace field = matador::utils::access;
|
||||||
namespace field = matador::utils::access;
|
field::primary_key( op, "id", id );
|
||||||
field::primary_key(op, "id", id);
|
field::attribute( op, "title", title, 511 );
|
||||||
field::attribute(op, "title", title, 511);
|
field::has_one( op, "author_id", book_author, matador::utils::default_foreign_attributes );
|
||||||
field::has_one(op, "author_id", book_author, matador::utils::default_foreign_attributes);
|
field::attribute( op, "published_in", published_in );
|
||||||
field::attribute(op, "published_in", published_in);
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QUERY_HELPER(authors, id, first_name, last_name, date_of_birth, year_of_birth, distinguished)
|
struct payload {
|
||||||
QUERY_HELPER(books, id, author_id, title, published_in)
|
unsigned long id{};
|
||||||
|
|
||||||
int main()
|
template<typename Operator>
|
||||||
|
void process( Operator& op ) {
|
||||||
|
namespace field = matador::utils::access;
|
||||||
|
field::primary_key( op, "id", id );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct job {
|
||||||
|
enum class job_state {
|
||||||
|
Pending,
|
||||||
|
Running,
|
||||||
|
Succeeded,
|
||||||
|
Failed,
|
||||||
|
Canceled
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class job_mode {
|
||||||
|
Foreground,
|
||||||
|
Background
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long id{};
|
||||||
|
matador::sql::entity<payload> payload;
|
||||||
|
std::string type;
|
||||||
|
std::string description;
|
||||||
|
job_state state;
|
||||||
|
job_mode mode;
|
||||||
|
|
||||||
|
template<typename Operator>
|
||||||
|
void process( Operator& op ) {
|
||||||
|
namespace field = matador::utils::access;
|
||||||
|
field::primary_key( op, "id", id );
|
||||||
|
field::belongs_to( op, "payload", payload, matador::utils::default_foreign_attributes );
|
||||||
|
field::attribute( op, "type", type, 511 );
|
||||||
|
field::attribute( op, "description", description, 511 );
|
||||||
|
field::attribute( op, "state", state );
|
||||||
|
field::attribute( op, "mode", mode );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const matador::utils::enum_mapper<job::job_state> job_state_enum({
|
||||||
|
{job::job_state::Pending, "Pending"},
|
||||||
|
{job::job_state::Running, "Running"},
|
||||||
|
{job::job_state::Succeeded, "Succeeded"},
|
||||||
|
{job::job_state::Failed, "Failed"},
|
||||||
|
{job::job_state::Canceled, "Canceled"}
|
||||||
|
});
|
||||||
|
|
||||||
|
static const matador::utils::enum_mapper<job::job_mode> job_mode_enum({
|
||||||
|
{job::job_mode::Foreground, "Foreground"},
|
||||||
|
{job::job_mode::Background, "Background"}
|
||||||
|
});
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct matador::sql::data_type_traits<job::job_state, void>
|
||||||
{
|
{
|
||||||
using namespace matador::sql;
|
inline static data_type_t builtin_type(std::size_t size)
|
||||||
using namespace matador;
|
{ return data_type_traits<std::string>::builtin_type(size); }
|
||||||
|
|
||||||
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
static void read_value(query_result_reader &reader, const char *id, size_t index, job::job_state &value)
|
||||||
|
{
|
||||||
|
std::string enum_string;
|
||||||
|
reader.read_value(id, index, enum_string, 64);
|
||||||
|
if (const auto enum_opt = job_state_enum.to_enum(enum_string)) {
|
||||||
|
value = enum_opt.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string dns{"sqlite://demo.db"};
|
static any_type create_value(const job::job_state &value)
|
||||||
schema s("main");
|
{
|
||||||
s.attach<author>("authors");
|
return job_state_enum.to_string(value);
|
||||||
s.attach<book>("books");
|
}
|
||||||
|
|
||||||
connection c(dns);
|
static void bind_value(parameter_binder &binder, size_t index, job::job_state &value)
|
||||||
c.open();
|
{
|
||||||
|
binder.bind(index, job_state_enum.to_string(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
auto create_authors_sql = c.query(s)
|
template<>
|
||||||
.create()
|
struct matador::sql::data_type_traits<job::job_mode, void>
|
||||||
.table<author>(qh::authors)
|
{
|
||||||
.execute();
|
inline static data_type_t builtin_type(std::size_t size)
|
||||||
|
{ return data_type_traits<std::string>::builtin_type(size); }
|
||||||
|
|
||||||
c.query(s)
|
static void read_value(query_result_reader &reader, const char *id, size_t index, job::job_mode &value)
|
||||||
.create()
|
{
|
||||||
.table<book>(qh::books)
|
std::string enum_string;
|
||||||
.execute();
|
reader.read_value(id, index, enum_string, 64);
|
||||||
|
if (const auto enum_opt = job_mode_enum.to_enum(enum_string)) {
|
||||||
|
value = enum_opt.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "SQL: " << create_authors_sql << "\n";
|
static any_type create_value(const job::job_mode &value)
|
||||||
|
{
|
||||||
|
return job_mode_enum.to_string(value);
|
||||||
|
}
|
||||||
|
|
||||||
author mc;
|
static void bind_value(parameter_binder &binder, size_t index, job::job_mode &value)
|
||||||
mc.id = 1;
|
{
|
||||||
mc.first_name = "Michael";
|
binder.bind(index, job_mode_enum.to_string(value));
|
||||||
mc.last_name = "Crichton";
|
}
|
||||||
mc.date_of_birth = "19.8.1954";
|
};
|
||||||
mc.year_of_birth = 1954;
|
|
||||||
mc.distinguished = true;
|
|
||||||
auto insert_authors_sql = c.query(s)
|
|
||||||
.insert()
|
|
||||||
.into(qh::authors)
|
|
||||||
.values(mc)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
std::cout << "SQL: " << insert_authors_sql << "\n";
|
QUERY_HELPER( authors, id, first_name, last_name, date_of_birth, year_of_birth, distinguished )
|
||||||
|
|
||||||
auto result = c.query(s)
|
QUERY_HELPER( books, id, author_id, title, published_in )
|
||||||
.select(qh::authors.columns)
|
|
||||||
.from(qh::authors)
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
for (const auto &row: result) {
|
QUERY_HELPER( job, id, payload, type, description, state, mode )
|
||||||
std::cout << "Author " << row.at(qh::authors.first_name) << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto update_authors_sql = c.query(s)
|
QUERY_HELPER( payload, id )
|
||||||
.update(qh::authors)
|
|
||||||
.set({{qh::authors.first_name, "Stephen"},
|
|
||||||
{qh::authors.last_name, "King"}})
|
|
||||||
.where(qh::authors.last_name == "Crichton")
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
std::cout << "SQL: " << update_authors_sql << "\n";
|
QUERY_HELPER( temporary_table, id );
|
||||||
|
|
||||||
auto authors = c.query(s)
|
int main() {
|
||||||
.select(qh::authors.columns)
|
using namespace matador::sql;
|
||||||
.from(qh::authors)
|
using namespace matador;
|
||||||
.fetch_all<author>();
|
|
||||||
|
|
||||||
for (const auto &a: authors) {
|
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
||||||
std::cout << "Author " << a.first_name << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
c.query(s)
|
std::string dns{"sqlite://demo.db"};
|
||||||
.insert()
|
schema s( "main" );
|
||||||
.into(qh::books)
|
s.attach<author>( "authors" );
|
||||||
.values({2, "It", mc.id, 1980})
|
s.attach<book>( "books" );
|
||||||
.execute();
|
|
||||||
|
|
||||||
c.query(s)
|
connection c( dns );
|
||||||
.insert()
|
c.open();
|
||||||
.into(qh::books)
|
s.create( c );
|
||||||
.values({3, "Misery", mc.id, 1984})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
auto select_books_sql = c.query(s)
|
auto create_authors_sql = c.query( s )
|
||||||
.select(qh::books.columns, {qh::authors.last_name})
|
.create()
|
||||||
.from(qh::books)
|
.table<author>( qh::authors )
|
||||||
.join_left(qh::authors)
|
.execute();
|
||||||
.on(qh::books.author_id == qh::authors.id)
|
|
||||||
.where(qh::books.published_in < 2008 && qh::authors.last_name == "King")
|
|
||||||
.group_by(qh::books.published_in)
|
|
||||||
.order_by(qh::books.title).asc()
|
|
||||||
.limit(5)
|
|
||||||
.offset(2)
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
for (const auto &r: select_books_sql) {
|
c.query( s )
|
||||||
std::cout << "R: " << r.at(qh::books.title) << ", " << r.at(qh::authors.last_name) << "\n";
|
.create()
|
||||||
}
|
.table<book>( qh::books )
|
||||||
// SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
.execute();
|
||||||
// FROM book
|
|
||||||
// INNER JOIN author ON book.author_id = author.id
|
|
||||||
// WHERE book.published_in < 2008 AND author.name = "Michael Crichton"
|
|
||||||
// ORDER BY "book.title" ASC
|
|
||||||
// OFFSET 2 LIMIT 5
|
|
||||||
|
|
||||||
c.query(s).drop().table(qh::books).execute();
|
std::cout << "SQL: " << create_authors_sql << "\n";
|
||||||
|
|
||||||
auto drop_authors_sql = c.query(s)
|
author mc;
|
||||||
.drop()
|
mc.id = 1;
|
||||||
.table(qh::authors)
|
mc.first_name = "Michael";
|
||||||
.execute();
|
mc.last_name = "Crichton";
|
||||||
|
mc.date_of_birth = "19.8.1954";
|
||||||
|
mc.year_of_birth = 1954;
|
||||||
|
mc.distinguished = true;
|
||||||
|
auto insert_authors_sql = c.query( s )
|
||||||
|
.insert()
|
||||||
|
.into( qh::authors )
|
||||||
|
.values( mc )
|
||||||
|
.execute();
|
||||||
|
|
||||||
std::cout << "SQL: " << drop_authors_sql << "\n";
|
std::cout << "SQL: " << insert_authors_sql << "\n";
|
||||||
|
|
||||||
return 0;
|
auto result = c.query( s )
|
||||||
|
.select( qh::authors.columns )
|
||||||
|
.from( qh::authors )
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
for (const auto& row: result) { std::cout << "Author " << row.at( qh::authors.first_name ) << "\n"; }
|
||||||
|
|
||||||
|
auto update_authors_sql = c.query( s )
|
||||||
|
.update( qh::authors )
|
||||||
|
.set( {{qh::authors.first_name, "Stephen"},
|
||||||
|
{qh::authors.last_name, "King"}} )
|
||||||
|
.where( qh::authors.last_name == "Crichton" )
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
std::cout << "SQL: " << update_authors_sql << "\n";
|
||||||
|
|
||||||
|
auto authors = c.query( s )
|
||||||
|
.select( qh::authors.columns )
|
||||||
|
.from( qh::authors )
|
||||||
|
.fetch_all<author>();
|
||||||
|
|
||||||
|
for (const auto& a: authors) { std::cout << "Author " << a.first_name << "\n"; }
|
||||||
|
|
||||||
|
c.query( s )
|
||||||
|
.insert()
|
||||||
|
.into( qh::books )
|
||||||
|
.values( {2, "It", mc.id, 1980} )
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
c.query( s )
|
||||||
|
.insert()
|
||||||
|
.into( qh::books )
|
||||||
|
.values( {3, "Misery", mc.id, 1984} )
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
auto select_books_sql = c.query( s )
|
||||||
|
.select( qh::books.columns, {qh::authors.last_name} )
|
||||||
|
.from( qh::books )
|
||||||
|
.join_left( qh::authors )
|
||||||
|
.on( qh::books.author_id == qh::authors.id )
|
||||||
|
.where( qh::books.published_in < 2008 && qh::authors.last_name == "King" )
|
||||||
|
.group_by( qh::books.published_in )
|
||||||
|
.order_by( qh::books.title ).asc()
|
||||||
|
.limit( 5 )
|
||||||
|
.offset( 2 )
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
for (const auto& r: select_books_sql) { std::cout << "R: " << r.at( qh::books.title ) << ", " << r.at( qh::authors.last_name ) << "\n"; }
|
||||||
|
// SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
||||||
|
// FROM book
|
||||||
|
// INNER JOIN author ON book.author_id = author.id
|
||||||
|
// WHERE book.published_in < 2008 AND author.name = "Michael Crichton"
|
||||||
|
// ORDER BY "book.title" ASC
|
||||||
|
// OFFSET 2 LIMIT 5
|
||||||
|
|
||||||
|
c.query( s ).drop().table( qh::books ).execute();
|
||||||
|
|
||||||
|
auto drop_authors_sql = c.query( s )
|
||||||
|
.drop()
|
||||||
|
.table( qh::authors )
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
std::cout << "SQL: " << drop_authors_sql << "\n";
|
||||||
|
|
||||||
|
auto res = c.query( s )
|
||||||
|
.select( {qh::payload.id} )
|
||||||
|
.from( qh::payload )
|
||||||
|
.join_left( qh::job )
|
||||||
|
.on( qh::job.payload == qh::payload.id )
|
||||||
|
.where(
|
||||||
|
in( qh::payload.id, c.query( s )
|
||||||
|
.select( {qh::job.state} )
|
||||||
|
.from( qh::job )
|
||||||
|
.where( qh::job.state == job::job_state::Running )
|
||||||
|
) &&
|
||||||
|
in( qh::payload.id, c.query( s )
|
||||||
|
.select( {qh::temporary_table.id} )
|
||||||
|
.from( qh::temporary_table ) )
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
// .fetch_value<unsigned long>();
|
||||||
|
std::cout << "SQL: " << res.sql << "\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef QUERY_COLUMN_HPP
|
|
||||||
#define QUERY_COLUMN_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class column {
|
|
||||||
public:
|
|
||||||
column(const char *name); // NOLINT(*-explicit-constructor)
|
|
||||||
column(std::string name); // NOLINT(*-explicit-constructor)
|
|
||||||
column(std::string table_name, std::string name, std::string as);
|
|
||||||
|
|
||||||
column& as(std::string a);
|
|
||||||
|
|
||||||
std::string table;
|
|
||||||
std::string name;
|
|
||||||
std::string alias;
|
|
||||||
};
|
|
||||||
|
|
||||||
column operator "" _col(const char *name, size_t len);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //QUERY_COLUMN_HPP
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_HPP
|
|
||||||
#define QUERY_QUERY_HPP
|
|
||||||
|
|
||||||
#include "matador/query/query_parts.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class connection;
|
|
||||||
class query
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query(connection &c);
|
|
||||||
|
|
||||||
query& select(const std::vector<column> &columns);
|
|
||||||
query& from(const std::string &table, const std::string &as = "");
|
|
||||||
|
|
||||||
private:
|
|
||||||
connection &connection_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_HPP
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_BUILDER_HPP
|
|
||||||
#define QUERY_QUERY_BUILDER_HPP
|
|
||||||
|
|
||||||
#include "matador/query/column.hpp"
|
|
||||||
#include "matador/query/query_intermediates.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/schema.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class query_builder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query_builder(const std::shared_ptr<sql::schema> &scm);
|
|
||||||
query_select_intermediate select(std::initializer_list<column> columns);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<sql::schema> schema_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_BUILDER_HPP
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_COMPILER_HPP
|
|
||||||
#define QUERY_QUERY_COMPILER_HPP
|
|
||||||
|
|
||||||
#include "matador/query/query_part_visitor.hpp"
|
|
||||||
#include "matador/query/query_parts.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#include <typeindex>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace matador::sql {
|
|
||||||
class dialect;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
struct query_data;
|
|
||||||
|
|
||||||
class query_compiler : public query_part_visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query_compiler(sql::dialect& d);
|
|
||||||
|
|
||||||
std::string compile(const query_data *data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void visit(query_select_part &select_part) override;
|
|
||||||
void visit(query_from_part &from_part) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
sql::dialect &dialect_;
|
|
||||||
std::string sql_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //QUERY_QUERY_COMPILER_HPP
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_DATA_HPP
|
|
||||||
#define QUERY_QUERY_DATA_HPP
|
|
||||||
|
|
||||||
#include "matador/query/query_parts.hpp"
|
|
||||||
#include "matador/query/sql_commands.hpp"
|
|
||||||
#include "matador/query/table.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
struct query_data
|
|
||||||
{
|
|
||||||
SqlCommands command;
|
|
||||||
std::vector<std::unique_ptr<query_part>> parts;
|
|
||||||
std::vector<column> columns;
|
|
||||||
std::unordered_map<std::type_index, table_data> table_map_by_index;
|
|
||||||
using table_data_ref = std::reference_wrapper<table_data>;
|
|
||||||
std::unordered_map<std::string, table_data_ref> table_map_by_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_DATA_HPP
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
|
|
||||||
#define QUERY_QUERY_INTERMEDIATES_HPP
|
|
||||||
|
|
||||||
#include "matador/sql/schema.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace matador::sql {
|
|
||||||
class basic_condition;
|
|
||||||
}
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class query_from_intermediate;
|
|
||||||
class query_join_intermediate;
|
|
||||||
class query_on_intermediate;
|
|
||||||
class query_where_intermediate;
|
|
||||||
class query_group_by_intermediate;
|
|
||||||
class query_order_by_intermediate;
|
|
||||||
class query_order_direction_intermediate;
|
|
||||||
class query_offset_intermediate;
|
|
||||||
class query_limit_intermediate;
|
|
||||||
|
|
||||||
class query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query_intermediate(const std::shared_ptr<sql::schema> &scm);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
sql::schema& schema() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<sql::schema> schema_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_select_finish_intermediate : public query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
void compile();
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_select_intermediate : public query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_from_intermediate from(const std::string &table, const std::string &as = "");
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_from_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_join_intermediate join(const std::string &join_table_name, const std::string &as);
|
|
||||||
query_where_intermediate where(const sql::basic_condition &cond);
|
|
||||||
query_group_by_intermediate group_by(const std::string &name);
|
|
||||||
query_order_by_intermediate order_by(const std::string &name);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_join_intermediate : public query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_on_intermediate on(const std::string &column, const std::string &join_column);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_on_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_join_intermediate join(const std::string &join_table_name, const std::string &as);
|
|
||||||
query_where_intermediate where(const sql::basic_condition &cond);
|
|
||||||
query_group_by_intermediate group_by(const std::string &name);
|
|
||||||
query_order_by_intermediate order_by(const std::string &name);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_where_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_group_by_intermediate group_by(const std::string &name);
|
|
||||||
query_order_by_intermediate order_by(const std::string &name);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_group_by_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_order_by_intermediate order_by(const std::string &name);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_order_by_intermediate : public query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_order_direction_intermediate asc();
|
|
||||||
query_order_direction_intermediate desc();
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_order_direction_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_offset_intermediate offset(size_t offset);
|
|
||||||
query_limit_intermediate limit(size_t limit);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_offset_intermediate : public query_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_intermediate::query_intermediate;
|
|
||||||
|
|
||||||
query_limit_intermediate limit(size_t limit);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_limit_intermediate : public query_select_finish_intermediate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish_intermediate::query_intermediate;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_INTERMEDIATES_HPP
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_PART_VISITOR_HPP
|
|
||||||
#define QUERY_QUERY_PART_VISITOR_HPP
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class query_select_part;
|
|
||||||
class query_from_part;
|
|
||||||
|
|
||||||
class query_part_visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~query_part_visitor() = default;
|
|
||||||
|
|
||||||
virtual void visit(query_select_part &select_part) = 0;
|
|
||||||
virtual void visit(query_from_part &from_part) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_PART_VISITOR_HPP
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#ifndef QUERY_QUERY_PARTS_HPP
|
|
||||||
#define QUERY_QUERY_PARTS_HPP
|
|
||||||
|
|
||||||
#include "matador/query/query_part_visitor.hpp"
|
|
||||||
#include "matador/query/column.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/dialect.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
class query_part
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
explicit query_part(sql::dialect::token_t token);
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~query_part() = default;
|
|
||||||
virtual void accept(query_part_visitor &visitor) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
sql::dialect::token_t token_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the SQL SELECT part
|
|
||||||
*/
|
|
||||||
class query_select_part : public query_part
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query_select_part(std::vector<column> columns);
|
|
||||||
void accept(query_part_visitor &visitor) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<column> columns_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the SQL FROM part
|
|
||||||
*/
|
|
||||||
class query_from_part : public query_part
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit query_from_part(std::string table_name);
|
|
||||||
query_from_part(std::string table_name, std::string as);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void accept(query_part_visitor &visitor) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string table_;
|
|
||||||
std::string alias_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_QUERY_PARTS_HPP
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#ifndef QUERY_SQL_COMMANDS_HPP
|
|
||||||
#define QUERY_SQL_COMMANDS_HPP
|
|
||||||
|
|
||||||
#include "matador/utils/enum_mapper.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
enum class SqlCommands
|
|
||||||
{
|
|
||||||
UNKNOWN, /**< Unknown query command */
|
|
||||||
CREATE, /**< Create query command */
|
|
||||||
DROP, /**< Drop query command */
|
|
||||||
SELECT, /**< Select query command */
|
|
||||||
INSERT, /**< Insert query command */
|
|
||||||
UPDATE, /**< Update query command */
|
|
||||||
REMOVE /**< Remove query command */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const utils::enum_mapper<SqlCommands> sql_command_enum({
|
|
||||||
{SqlCommands::UNKNOWN, "unknown"},
|
|
||||||
{SqlCommands::CREATE, "create"},
|
|
||||||
{SqlCommands::DROP, "drop"},
|
|
||||||
{SqlCommands::SELECT, "select"},
|
|
||||||
{SqlCommands::INSERT, "insert"},
|
|
||||||
{SqlCommands::UPDATE, "update"},
|
|
||||||
{SqlCommands::REMOVE, "delete"}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //QUERY_SQL_COMMANDS_HPP
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef QUERY_TABLE_HPP
|
|
||||||
#define QUERY_TABLE_HPP
|
|
||||||
|
|
||||||
#include <typeindex>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
struct table_data
|
|
||||||
{
|
|
||||||
std::type_index index;
|
|
||||||
std::string name;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_TABLE_HPP
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef QUERY_CONDITION_HPP
|
#ifndef QUERY_CONDITION_HPP
|
||||||
#define QUERY_CONDITION_HPP
|
#define QUERY_CONDITION_HPP
|
||||||
|
|
||||||
|
#include "matador/sql/any_type_to_string_visitor.hpp"
|
||||||
|
#include "matador/sql/query_result.hpp"
|
||||||
#include "matador/sql/basic_condition.hpp"
|
#include "matador/sql/basic_condition.hpp"
|
||||||
#include "matador/sql/dialect.hpp"
|
#include "matador/sql/dialect.hpp"
|
||||||
#include "matador/sql/placeholder.hpp"
|
#include "matador/sql/placeholder.hpp"
|
||||||
@@ -26,6 +28,8 @@ namespace matador::sql {
|
|||||||
|
|
||||||
/// @cond MATADOR_DEV
|
/// @cond MATADOR_DEV
|
||||||
|
|
||||||
|
class query_select;
|
||||||
|
|
||||||
template<class L, class R, class Enabled = void>
|
template<class L, class R, class Enabled = void>
|
||||||
class condition;
|
class condition;
|
||||||
|
|
||||||
@@ -43,6 +47,7 @@ public:
|
|||||||
template<class T>
|
template<class T>
|
||||||
class condition<column, T, typename std::enable_if<
|
class condition<column, T, typename std::enable_if<
|
||||||
std::is_scalar<T>::value &&
|
std::is_scalar<T>::value &&
|
||||||
|
!std::is_enum<T>::value &&
|
||||||
!std::is_same<std::string, T>::value &&
|
!std::is_same<std::string, T>::value &&
|
||||||
!std::is_same<const char*, T>::value>::type> : public basic_column_condition
|
!std::is_same<const char*, T>::value>::type> : public basic_column_condition
|
||||||
{
|
{
|
||||||
@@ -82,10 +87,32 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class condition<T, column, typename std::enable_if<
|
class condition<column, T, std::enable_if_t<std::is_enum_v<T>>> final : public basic_column_condition
|
||||||
std::is_scalar<T>::value &&
|
{
|
||||||
!std::is_same<std::string, T>::value &&
|
public:
|
||||||
!std::is_same<const char*, T>::value>::type> : public basic_column_condition
|
condition(const column &fld, basic_condition::operand_t op, T val)
|
||||||
|
: basic_column_condition(fld, op)
|
||||||
|
, value(val)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
T value;
|
||||||
|
|
||||||
|
std::string evaluate(const dialect &d, query_context &query) const override
|
||||||
|
{
|
||||||
|
auto at = data_type_traits<T>::create_value(value);
|
||||||
|
any_type_to_string_visitor value_to_string(d, query);
|
||||||
|
std::visit(value_to_string, at);
|
||||||
|
return value_to_string.result + " " + operand + " " + d.prepare_identifier(field_);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class condition<T, column, std::enable_if_t<
|
||||||
|
std::is_scalar_v<T> &&
|
||||||
|
!std::is_same_v<std::string, T> &&
|
||||||
|
!std::is_same_v<const char*, T>>> final : public basic_column_condition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
condition(T val, basic_condition::operand_t op, const column &fld)
|
condition(T val, basic_condition::operand_t op, const column &fld)
|
||||||
@@ -215,7 +242,7 @@ public:
|
|||||||
* @param op Operand of the condition
|
* @param op Operand of the condition
|
||||||
* @param q The query to be evaluated to the IN arguments
|
* @param q The query to be evaluated to the IN arguments
|
||||||
*/
|
*/
|
||||||
condition(column col, basic_condition::operand_t op, query_context &q);
|
condition(column col, basic_condition::operand_t op, const query_context &q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluates the condition
|
* @brief Evaluates the condition
|
||||||
@@ -229,7 +256,7 @@ public:
|
|||||||
std::string evaluate(const dialect &d, query_context &query) const override;
|
std::string evaluate(const dialect &d, query_context &query) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
query_context &query_;
|
query_context query_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,7 +442,8 @@ condition<column, std::initializer_list<V>> in(const column &col, std::initializ
|
|||||||
* @param q The query to be executes as sub select
|
* @param q The query to be executes as sub select
|
||||||
* @return The condition object
|
* @return The condition object
|
||||||
*/
|
*/
|
||||||
condition<column, query_context> in(const column &col, query_context &&q);
|
condition<column, query_context> in(const column &col, const query_context &q);
|
||||||
|
condition<column, query_context> in(const column &col, const query_select &q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a between condition.
|
* @brief Creates a between condition.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -86,19 +87,21 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
connection_pointer acquire() {
|
connection_pointer acquire() {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
while (idle_connections_.empty()) {
|
||||||
|
cv.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_next_connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_pointer try_acquire() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
if (idle_connections_.empty()) {
|
if (idle_connections_.empty()) {
|
||||||
return {nullptr, this};
|
return {nullptr, this};
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer next_connection{nullptr};
|
return get_next_connection();
|
||||||
for (auto &item : idle_connections_) {
|
|
||||||
next_connection = item.second;
|
|
||||||
auto node = idle_connections_.extract(item.first);
|
|
||||||
inuse_connections_.insert(std::move(node));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {next_connection, this};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_pointer acquire(size_t id) {
|
connection_pointer acquire(size_t id) {
|
||||||
@@ -151,8 +154,21 @@ public:
|
|||||||
const connection_info &info() const {
|
const connection_info &info() const {
|
||||||
return info_;
|
return info_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
connection_pointer get_next_connection() {
|
||||||
|
pointer next_connection{nullptr};
|
||||||
|
for (auto &item : idle_connections_) {
|
||||||
|
next_connection = item.second;
|
||||||
|
auto node = idle_connections_.extract(item.first);
|
||||||
|
inuse_connections_.insert(std::move(node));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {next_connection, this};
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
|
std::condition_variable cv;
|
||||||
std::vector<IdConnection<Connection>> connection_repo_;
|
std::vector<IdConnection<Connection>> connection_repo_;
|
||||||
using pointer = IdConnection<Connection>*;
|
using pointer = IdConnection<Connection>*;
|
||||||
using connection_map = std::unordered_map<size_t, pointer>;
|
using connection_map = std::unordered_map<size_t, pointer>;
|
||||||
|
|||||||
@@ -53,13 +53,22 @@ template < class Type, class Enable = void >
|
|||||||
struct data_type_traits;
|
struct data_type_traits;
|
||||||
|
|
||||||
/// @cond MATADOR_DEV
|
/// @cond MATADOR_DEV
|
||||||
|
template <> struct data_type_traits<nullptr_t, void>
|
||||||
|
{
|
||||||
|
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_null; }
|
||||||
|
static void read_value(query_result_reader &reader, const char *id, size_t index, nullptr_t &/*value*/);
|
||||||
|
static void bind_value(parameter_binder &binder, size_t index, nullptr_t &/*value*/);
|
||||||
|
static void bind_result_value(result_parameter_binder &binder, size_t index, nullptr_t &/*value*/);
|
||||||
|
inline static any_type create_value(const char &value) { return value; }
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<char, void>
|
template <> struct data_type_traits<char, void>
|
||||||
{
|
{
|
||||||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
|
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, char &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, char &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, char &value);
|
static void bind_value(parameter_binder &binder, size_t index, char &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, char &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, char &value);
|
||||||
inline static any_type create_value(char &value) { return value; }
|
inline static any_type create_value(const char &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<short, void>
|
template <> struct data_type_traits<short, void>
|
||||||
@@ -68,7 +77,7 @@ template <> struct data_type_traits<short, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, short &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, short &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, short &value);
|
static void bind_value(parameter_binder &binder, size_t index, short &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, short &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, short &value);
|
||||||
inline static any_type create_value(short &value) { return value; }
|
inline static any_type create_value(const short &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<int, void>
|
template <> struct data_type_traits<int, void>
|
||||||
@@ -77,7 +86,7 @@ template <> struct data_type_traits<int, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, int &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, int &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, int &value);
|
static void bind_value(parameter_binder &binder, size_t index, int &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, int &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, int &value);
|
||||||
inline static any_type create_value(int &value) { return value; }
|
inline static any_type create_value(const int &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<long, void>
|
template <> struct data_type_traits<long, void>
|
||||||
@@ -86,7 +95,7 @@ template <> struct data_type_traits<long, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, long &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, long &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, long &value);
|
static void bind_value(parameter_binder &binder, size_t index, long &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, long &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, long &value);
|
||||||
inline static any_type create_value(long &value) { return value; }
|
inline static any_type create_value(const long &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<long long, void>
|
template <> struct data_type_traits<long long, void>
|
||||||
@@ -95,7 +104,7 @@ template <> struct data_type_traits<long long, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, long long &value);
|
static void bind_value(parameter_binder &binder, size_t index, long long &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, long long &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, long long &value);
|
||||||
inline static any_type create_value(long long &value) { return value; }
|
inline static any_type create_value(const long long &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<unsigned char, void>
|
template <> struct data_type_traits<unsigned char, void>
|
||||||
@@ -104,7 +113,7 @@ template <> struct data_type_traits<unsigned char, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, unsigned char &value);
|
static void bind_value(parameter_binder &binder, size_t index, unsigned char &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned char &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned char &value);
|
||||||
inline static any_type create_value(unsigned char &value) { return value; }
|
inline static any_type create_value(const unsigned char &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<unsigned short, void>
|
template <> struct data_type_traits<unsigned short, void>
|
||||||
@@ -113,7 +122,7 @@ template <> struct data_type_traits<unsigned short, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, unsigned short &value);
|
static void bind_value(parameter_binder &binder, size_t index, unsigned short &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned short &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned short &value);
|
||||||
inline static any_type create_value(unsigned short &value) { return value; }
|
inline static any_type create_value(const unsigned short &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<unsigned int, void>
|
template <> struct data_type_traits<unsigned int, void>
|
||||||
@@ -122,7 +131,7 @@ template <> struct data_type_traits<unsigned int, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, unsigned int &value);
|
static void bind_value(parameter_binder &binder, size_t index, unsigned int &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned int &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned int &value);
|
||||||
inline static any_type create_value(unsigned int &value) { return value; }
|
inline static any_type create_value(const unsigned int &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<unsigned long, void>
|
template <> struct data_type_traits<unsigned long, void>
|
||||||
@@ -131,7 +140,7 @@ template <> struct data_type_traits<unsigned long, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, unsigned long &value);
|
static void bind_value(parameter_binder &binder, size_t index, unsigned long &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long &value);
|
||||||
inline static any_type create_value(unsigned long &value) { return value; }
|
inline static any_type create_value(const unsigned long &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<unsigned long long, void>
|
template <> struct data_type_traits<unsigned long long, void>
|
||||||
@@ -140,7 +149,7 @@ template <> struct data_type_traits<unsigned long long, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value);
|
static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long long &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, unsigned long long &value);
|
||||||
inline static any_type create_value(unsigned long long &value) { return value; }
|
inline static any_type create_value(const unsigned long long &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<bool, void>
|
template <> struct data_type_traits<bool, void>
|
||||||
@@ -149,7 +158,7 @@ template <> struct data_type_traits<bool, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, bool &value);
|
static void bind_value(parameter_binder &binder, size_t index, bool &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, bool &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, bool &value);
|
||||||
inline static any_type create_value(bool &value) { return value; }
|
inline static any_type create_value(const bool &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<float, void>
|
template <> struct data_type_traits<float, void>
|
||||||
@@ -158,7 +167,7 @@ template <> struct data_type_traits<float, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, float &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, float &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, float &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, float &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, float &value);
|
static void bind_value(parameter_binder &binder, size_t index, float &value);
|
||||||
inline static any_type create_value(float &value) { return value; }
|
inline static any_type create_value(const float &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<double, void>
|
template <> struct data_type_traits<double, void>
|
||||||
@@ -167,7 +176,7 @@ template <> struct data_type_traits<double, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, double &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, double &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, double &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, double &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, double &value);
|
static void bind_value(parameter_binder &binder, size_t index, double &value);
|
||||||
inline static any_type create_value(double &value) { return value; }
|
inline static any_type create_value(const double &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<const char*, void>
|
template <> struct data_type_traits<const char*, void>
|
||||||
@@ -194,16 +203,16 @@ template <> struct data_type_traits<std::string, void>
|
|||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
|
||||||
inline static any_type create_value(std::string &value) { return value; }
|
inline static any_type create_value(const std::string &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct data_type_traits<utils::blob, void>
|
template <> struct data_type_traits<utils::blob, void>
|
||||||
{
|
{
|
||||||
inline static data_type_t builtin_type(std::size_t size) { return data_type_t::type_blob; }
|
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_blob; }
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, utils::blob &value);
|
static void read_value(query_result_reader &reader, const char *id, size_t index, utils::blob &value);
|
||||||
static void bind_value(parameter_binder &binder, size_t index, utils::blob &value);
|
static void bind_value(parameter_binder &binder, size_t index, utils::blob &value);
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, utils::blob &value);
|
static void bind_result_value(result_parameter_binder &binder, size_t index, utils::blob &value);
|
||||||
inline static any_type create_value(utils::blob &value) { return value; }
|
inline static any_type create_value(const utils::blob &value) { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//template <> struct data_type_traits<matador::date>
|
//template <> struct data_type_traits<matador::date>
|
||||||
@@ -223,7 +232,7 @@ template <> struct data_type_traits<utils::blob, void>
|
|||||||
//};
|
//};
|
||||||
|
|
||||||
template < typename EnumType >
|
template < typename EnumType >
|
||||||
struct data_type_traits<EnumType, typename std::enable_if<std::is_enum<EnumType>::value>::type>
|
struct data_type_traits<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>>
|
||||||
{
|
{
|
||||||
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
|
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value)
|
static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value)
|
||||||
@@ -232,13 +241,15 @@ struct data_type_traits<EnumType, typename std::enable_if<std::is_enum<EnumType>
|
|||||||
}
|
}
|
||||||
static void bind_value(parameter_binder &binder, size_t index, EnumType &value)
|
static void bind_value(parameter_binder &binder, size_t index, EnumType &value)
|
||||||
{
|
{
|
||||||
data_type_traits<int>::bind_value(binder, index, (int&)value);
|
data_type_traits<int>::bind_value(binder, index, static_cast<int&>(value));
|
||||||
}
|
}
|
||||||
static void bind_result_value(result_parameter_binder &binder, size_t index, EnumType &value)
|
static void bind_result_value(result_parameter_binder &binder, size_t index, EnumType &value)
|
||||||
{
|
{
|
||||||
data_type_traits<int>::bind_result_value(binder, index, (int&)value);
|
data_type_traits<int>::bind_result_value(binder, index, static_cast<int&>(value));
|
||||||
|
}
|
||||||
|
static any_type create_value(const EnumType &value) {
|
||||||
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
inline static any_type create_value(EnumType &value) { return (int)value; }
|
|
||||||
};
|
};
|
||||||
/// @endcond
|
/// @endcond
|
||||||
|
|
||||||
|
|||||||
@@ -6,68 +6,149 @@
|
|||||||
#include "matador/sql/query_context.hpp"
|
#include "matador/sql/query_context.hpp"
|
||||||
#include "matador/sql/query.hpp"
|
#include "matador/sql/query.hpp"
|
||||||
#include "matador/sql/query_intermediates.hpp"
|
#include "matador/sql/query_intermediates.hpp"
|
||||||
|
#include "matador/sql/value.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/result.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
struct join_data
|
struct join_columns
|
||||||
{
|
{
|
||||||
table join_table;
|
std::string join_column;
|
||||||
std::unique_ptr<basic_condition> condition;
|
std::string inverse_join_column;
|
||||||
|
};
|
||||||
|
|
||||||
|
class join_column_collector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class Type>
|
||||||
|
join_columns collect()
|
||||||
|
{
|
||||||
|
join_columns_ = {};
|
||||||
|
Type obj;
|
||||||
|
|
||||||
|
matador::utils::access::process(*this, obj);
|
||||||
|
|
||||||
|
return join_columns_;
|
||||||
|
}
|
||||||
|
template < class V >
|
||||||
|
void on_primary_key(const char * /*id*/, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0) {}
|
||||||
|
void on_primary_key(const char * /*id*/, std::string &, size_t) {}
|
||||||
|
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
|
||||||
|
template<typename Type>
|
||||||
|
void on_attribute(const char * /*id*/, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_belongs_to(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many(ContainerType &, const char *join_column, const utils::foreign_attributes &attr) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many_to_many(const char * /*id*/, ContainerType &/*c*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/)
|
||||||
|
{
|
||||||
|
join_columns_.join_column = join_column;
|
||||||
|
join_columns_.inverse_join_column = inverse_join_column;
|
||||||
|
}
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many_to_many(const char * /*id*/, ContainerType &/*c*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
join_columns join_columns_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct entity_query_data {
|
struct entity_query_data {
|
||||||
std::string root_table_name;
|
std::string root_table_name;
|
||||||
|
std::string pk_column_;
|
||||||
std::vector<column> columns;
|
std::vector<column> columns;
|
||||||
std::vector<join_data> joins;
|
std::vector<join_data> joins;
|
||||||
std::unique_ptr<basic_condition> where_clause;
|
std::unique_ptr<basic_condition> where_clause;
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename PrimaryKeyType >
|
enum class query_build_error : std::uint8_t {
|
||||||
|
Ok = 0,
|
||||||
|
UnknownType,
|
||||||
|
MissingPrimaryKey,
|
||||||
|
UnexpectedError
|
||||||
|
};
|
||||||
|
|
||||||
|
class query_builder_exception : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit query_builder_exception(query_build_error error) : error_(error) {}
|
||||||
|
|
||||||
|
[[nodiscard]] query_build_error error() const { return error_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const query_build_error error_;
|
||||||
|
};
|
||||||
|
|
||||||
class entity_query_builder
|
class entity_query_builder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit entity_query_builder(const PrimaryKeyType &pk, const schema &scm)
|
explicit entity_query_builder(const schema &scm)
|
||||||
: pk_(pk)
|
: schema_(scm) {}
|
||||||
, schema_(scm) {}
|
|
||||||
|
|
||||||
template<class EntityType>
|
template<class EntityType, typename PrimaryKeyType>
|
||||||
std::optional<entity_query_data> build() {
|
utils::result<entity_query_data, query_build_error> build(const PrimaryKeyType &pk) {
|
||||||
const auto info = schema_.info<EntityType>();
|
const auto info = schema_.info<EntityType>();
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return std::nullopt;
|
return utils::error(query_build_error::UnknownType);
|
||||||
}
|
}
|
||||||
|
pk_ = pk;
|
||||||
table_info_stack_.push(info.value());
|
table_info_stack_.push(info.value());
|
||||||
entity_query_data_ = { info->name };
|
entity_query_data_ = { info->name };
|
||||||
EntityType obj;
|
EntityType obj;
|
||||||
matador::utils::access::process(*this, obj);
|
try {
|
||||||
|
matador::utils::access::process(*this, obj);
|
||||||
|
|
||||||
return std::move(entity_query_data_);
|
return {utils::ok(std::move(entity_query_data_))};
|
||||||
|
} catch (const query_builder_exception &ex) {
|
||||||
|
return {utils::error(ex.error())};
|
||||||
|
} catch (...) {
|
||||||
|
return {utils::error(query_build_error::UnexpectedError)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class EntityType>
|
||||||
|
utils::result<entity_query_data, query_build_error> build() {
|
||||||
|
const auto info = schema_.info<EntityType>();
|
||||||
|
if (!info) {
|
||||||
|
return utils::error(query_build_error::UnknownType);
|
||||||
|
}
|
||||||
|
pk_ = nullptr;
|
||||||
|
table_info_stack_.push(info.value());
|
||||||
|
entity_query_data_ = { info->name };
|
||||||
|
EntityType obj;
|
||||||
|
try {
|
||||||
|
matador::utils::access::process(*this, obj);
|
||||||
|
|
||||||
|
return {utils::ok(std::move(entity_query_data_))};
|
||||||
|
} catch (const query_builder_exception &ex) {
|
||||||
|
return {utils::error(ex.error())};
|
||||||
|
} catch (...) {
|
||||||
|
return {utils::error(query_build_error::UnexpectedError)};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template < class V >
|
template < class V >
|
||||||
void on_primary_key(const char *id, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
|
void on_primary_key(const char *id, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
|
||||||
{
|
|
||||||
push(id);
|
|
||||||
if (is_root_entity() && std::is_integral_v<PrimaryKeyType>) {
|
|
||||||
entity_query_data_.where_clause = make_condition(column{table_info_stack_.top().name, id, ""} == pk_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void on_primary_key(const char *id, std::string &, size_t)
|
|
||||||
{
|
{
|
||||||
push(id);
|
push(id);
|
||||||
if (!is_root_entity()) {
|
if (!is_root_entity()) {
|
||||||
auto b = std::is_same_v<PrimaryKeyType, std::string>;
|
return;
|
||||||
std::cout << "is matching primary key: " << std::boolalpha << b << "\n";
|
}
|
||||||
|
if (pk_.is_null()) {
|
||||||
|
entity_query_data_.pk_column_ = id;
|
||||||
|
} else if (pk_.is_integer()) {
|
||||||
|
entity_query_data_.where_clause = make_condition(column{table_info_stack_.top().name, id, ""} == *pk_.as<V>());
|
||||||
|
entity_query_data_.pk_column_ = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_revision(const char *id, unsigned long long &/*rev*/)
|
void on_primary_key(const char *id, std::string &, size_t);
|
||||||
{
|
void on_revision(const char *id, unsigned long long &/*rev*/);
|
||||||
push(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
|
||||||
@@ -76,51 +157,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr)
|
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
|
||||||
{
|
{
|
||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
on_foreign_object(id, obj, attr);
|
||||||
const auto info = schema_.info<typename Pointer::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
table_info_stack_.push(info.value());
|
|
||||||
typename Pointer::value_type obj;
|
|
||||||
matador::utils::access::process(*this , obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
auto pk = info->prototype.primary_key();
|
|
||||||
if (!pk) {
|
|
||||||
// error, prototype doesn't has a pk
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
|
|
||||||
} else {
|
|
||||||
push(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr)
|
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
|
||||||
{
|
{
|
||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
on_foreign_object(id, obj, attr);
|
||||||
const auto info = schema_.info<typename Pointer::value_type>();
|
|
||||||
if (!info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
table_info_stack_.push(info.value());
|
|
||||||
typename Pointer::value_type obj;
|
|
||||||
matador::utils::access::process(*this, obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
auto pk = info->prototype.primary_key();
|
|
||||||
if (!pk) {
|
|
||||||
// error, prototype doesn't has a pk
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
|
|
||||||
} else {
|
|
||||||
push(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
@@ -129,7 +174,7 @@ public:
|
|||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
if (attr.fetch() == utils::fetch_type::EAGER) {
|
||||||
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return;
|
throw query_builder_exception{query_build_error::UnknownType};
|
||||||
}
|
}
|
||||||
table_info_stack_.push(info.value());
|
table_info_stack_.push(info.value());
|
||||||
typename ContainerType::value_type::value_type obj;
|
typename ContainerType::value_type::value_type obj;
|
||||||
@@ -138,8 +183,7 @@ public:
|
|||||||
|
|
||||||
auto pk = info->prototype.primary_key();
|
auto pk = info->prototype.primary_key();
|
||||||
if (!pk) {
|
if (!pk) {
|
||||||
// error, prototype doesn't has a pk
|
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {info->name, join_column});
|
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {info->name, join_column});
|
||||||
@@ -149,56 +193,91 @@ public:
|
|||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr)
|
void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr)
|
||||||
{
|
{
|
||||||
if (attr.fetch() == utils::fetch_type::EAGER) {
|
if (attr.fetch() != utils::fetch_type::EAGER) {
|
||||||
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
return;
|
||||||
if (!info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
table_info_stack_.push(info.value());
|
|
||||||
typename ContainerType::value_type::value_type obj;
|
|
||||||
matador::utils::access::process(*this , obj);
|
|
||||||
table_info_stack_.pop();
|
|
||||||
|
|
||||||
auto pk = info->prototype.primary_key();
|
|
||||||
if (!pk) {
|
|
||||||
// error, prototype doesn't has a pk
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {id, join_column});
|
|
||||||
append_join({info->name, pk->name()}, {id, inverse_join_column});
|
|
||||||
}
|
}
|
||||||
|
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
||||||
|
if (!info) {
|
||||||
|
throw query_builder_exception{query_build_error::UnknownType};
|
||||||
|
}
|
||||||
|
table_info_stack_.push(info.value());
|
||||||
|
typename ContainerType::value_type::value_type obj;
|
||||||
|
matador::utils::access::process(*this , obj);
|
||||||
|
table_info_stack_.pop();
|
||||||
|
|
||||||
|
auto pk = info->prototype.primary_key();
|
||||||
|
if (!pk) {
|
||||||
|
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
||||||
|
}
|
||||||
|
|
||||||
|
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {id, join_column});
|
||||||
|
append_join({id, inverse_join_column}, {info->name, pk->name()});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
|
void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
|
||||||
|
{
|
||||||
|
if (attr.fetch() != utils::fetch_type::EAGER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto info = schema_.info<typename ContainerType::value_type::value_type>();
|
||||||
|
if (!info) {
|
||||||
|
throw query_builder_exception{query_build_error::UnknownType};
|
||||||
|
}
|
||||||
|
table_info_stack_.push(info.value());
|
||||||
|
typename ContainerType::value_type::value_type obj;
|
||||||
|
matador::utils::access::process(*this , obj);
|
||||||
|
table_info_stack_.pop();
|
||||||
|
|
||||||
|
auto pk = info->prototype.primary_key();
|
||||||
|
if (!pk) {
|
||||||
|
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto join_columns = join_column_collector_.collect<typename ContainerType::value_type::value_type>();
|
||||||
|
|
||||||
|
append_join({table_info_stack_.top().name, table_info_stack_.top().prototype.primary_key()->name()}, {id, join_columns.inverse_join_column});
|
||||||
|
append_join({id, join_columns.join_column}, {info->name, pk->name()});
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void push(const std::string &column_name)
|
template<class Pointer>
|
||||||
{
|
void on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr);
|
||||||
char str[4];
|
void push(const std::string &column_name);
|
||||||
snprintf(str, 4, "c%02d", ++column_index);
|
[[nodiscard]] bool is_root_entity() const;
|
||||||
entity_query_data_.columns.emplace_back(table_info_stack_.top().name, column_name, str);
|
void append_join(const column &left, const column &right);
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool is_root_entity() const {
|
|
||||||
return table_info_stack_.size() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append_join(const column &left, const column &right)
|
|
||||||
{
|
|
||||||
entity_query_data_.joins.push_back({
|
|
||||||
{ left.table },
|
|
||||||
make_condition(left == right)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
PrimaryKeyType pk_;
|
value pk_;
|
||||||
std::stack<table_info> table_info_stack_;
|
std::stack<table_info> table_info_stack_;
|
||||||
const schema &schema_;
|
const schema &schema_;
|
||||||
entity_query_data entity_query_data_;
|
entity_query_data entity_query_data_;
|
||||||
int column_index{0};
|
int column_index{0};
|
||||||
|
join_column_collector join_column_collector_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Pointer>
|
||||||
|
void entity_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr)
|
||||||
|
{
|
||||||
|
if (attr.fetch() == utils::fetch_type::EAGER) {
|
||||||
|
const auto info = schema_.info<typename Pointer::value_type>();
|
||||||
|
if (!info) {
|
||||||
|
throw query_builder_exception{query_build_error::UnknownType};
|
||||||
|
}
|
||||||
|
table_info_stack_.push(info.value());
|
||||||
|
typename Pointer::value_type obj;
|
||||||
|
matador::utils::access::process(*this, obj);
|
||||||
|
table_info_stack_.pop();
|
||||||
|
|
||||||
|
auto pk = info->prototype.primary_key();
|
||||||
|
if (!pk) {
|
||||||
|
throw query_builder_exception{query_build_error::MissingPrimaryKey};
|
||||||
|
}
|
||||||
|
append_join({table_info_stack_.top().name, id}, {info->name, pk->name()});
|
||||||
|
} else {
|
||||||
|
push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP
|
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
#ifndef QUERY_FIELD_HPP
|
#ifndef QUERY_FIELD_HPP
|
||||||
#define QUERY_FIELD_HPP
|
#define QUERY_FIELD_HPP
|
||||||
|
|
||||||
#include "matador/sql/any_type.hpp"
|
#include "matador/sql/value.hpp"
|
||||||
#include "matador/sql/any_type_to_visitor.hpp"
|
|
||||||
#include "matador/sql/data_type_traits.hpp"
|
|
||||||
|
|
||||||
#include "matador/utils/types.hpp"
|
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -19,10 +15,8 @@ public:
|
|||||||
template<typename Type>
|
template<typename Type>
|
||||||
field(std::string name, Type value, size_t size = 0, int index = -1)
|
field(std::string name, Type value, size_t size = 0, int index = -1)
|
||||||
: name_(std::move(name))
|
: name_(std::move(name))
|
||||||
, size_(size)
|
|
||||||
, index_(index)
|
, index_(index)
|
||||||
, value_(value)
|
, value_(value, size) {}
|
||||||
, type_(data_type_traits<Type>::builtin_type(size)) {}
|
|
||||||
field(std::string name, data_type_t data_type, size_t size = 0, int index = -1);
|
field(std::string name, data_type_t data_type, size_t size = 0, int index = -1);
|
||||||
field(const field &x) = default;
|
field(const field &x) = default;
|
||||||
field& operator=(const field &x) = default;
|
field& operator=(const field &x) = default;
|
||||||
@@ -32,7 +26,7 @@ public:
|
|||||||
template<typename Type>
|
template<typename Type>
|
||||||
field& operator=(Type value) {
|
field& operator=(Type value) {
|
||||||
value_ = std::move(value);
|
value_ = std::move(value);
|
||||||
type_ = data_type_traits<Type>::builtin_type(-1);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +37,7 @@ public:
|
|||||||
template<class Type>
|
template<class Type>
|
||||||
std::optional<Type> as() const
|
std::optional<Type> as() const
|
||||||
{
|
{
|
||||||
any_type_to_visitor<Type> visitor;
|
return value_.as<Type>();
|
||||||
std::visit(visitor, const_cast<any_type&>(value_));
|
|
||||||
return visitor.result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string str() const;
|
[[nodiscard]] std::string str() const;
|
||||||
@@ -65,7 +57,7 @@ private:
|
|||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op)
|
void process(Operator &op)
|
||||||
{
|
{
|
||||||
op.on_attribute(name_.c_str(), value_, type_, size_);
|
op.on_attribute(name_.c_str(), value_, value_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -73,9 +65,8 @@ private:
|
|||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
int index_{-1};
|
int index_{-1};
|
||||||
any_type value_;
|
|
||||||
size_t size_{};
|
value value_;
|
||||||
data_type_t type_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ protected:
|
|||||||
class query_intermediate : public basic_query_intermediate
|
class query_intermediate : public basic_query_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
query_intermediate(connection &db, const sql::schema &schema, query_data &data);
|
query_intermediate(connection &db, const sql::schema &schema, const std::shared_ptr<query_data> &data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
query_data &data_;
|
std::shared_ptr<query_data> data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_execute_finish : public query_intermediate
|
class query_execute : public query_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_intermediate::query_intermediate;
|
using query_intermediate::query_intermediate;
|
||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
[[nodiscard]] query_context build() const;
|
[[nodiscard]] query_context build() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_select_finish : public query_intermediate
|
class query_select : public query_intermediate
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
using query_intermediate::query_intermediate;
|
using query_intermediate::query_intermediate;
|
||||||
@@ -64,15 +64,15 @@ public:
|
|||||||
query_result<record> fetch_all();
|
query_result<record> fetch_all();
|
||||||
|
|
||||||
template < class Type >
|
template < class Type >
|
||||||
std::optional<Type> fetch_one()
|
std::unique_ptr<Type> fetch_one()
|
||||||
{
|
{
|
||||||
auto result = query_result<Type>(fetch());
|
auto result = query_result<Type>(fetch());
|
||||||
auto first = result.begin();
|
auto first = result.begin();
|
||||||
if (first == result.end()) {
|
if (first == result.end()) {
|
||||||
return std::nullopt;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *first.get();
|
return std::unique_ptr<Type>{first.release()};
|
||||||
}
|
}
|
||||||
std::optional<record> fetch_one();
|
std::optional<record> fetch_one();
|
||||||
|
|
||||||
@@ -96,36 +96,36 @@ private:
|
|||||||
|
|
||||||
class query_offset_intermediate;
|
class query_offset_intermediate;
|
||||||
|
|
||||||
class query_limit_intermediate : public query_select_finish
|
class query_limit_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_offset_intermediate offset(size_t offset);
|
query_offset_intermediate offset(size_t offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_offset_intermediate : public query_select_finish
|
class query_offset_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_limit_intermediate limit(size_t limit);
|
query_limit_intermediate limit(size_t limit);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_order_direction_intermediate : public query_select_finish
|
class query_order_direction_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_limit_intermediate limit(size_t limit);
|
query_limit_intermediate limit(size_t limit);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_order_by_intermediate;
|
class query_order_by_intermediate;
|
||||||
|
|
||||||
class query_group_by_intermediate : public query_select_finish
|
class query_group_by_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_order_by_intermediate order_by(const column &col);
|
query_order_by_intermediate order_by(const column &col);
|
||||||
};
|
};
|
||||||
@@ -139,10 +139,10 @@ public:
|
|||||||
query_order_direction_intermediate desc();
|
query_order_direction_intermediate desc();
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_where_intermediate : public query_select_finish
|
class query_where_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_group_by_intermediate group_by(const column &col);
|
query_group_by_intermediate group_by(const column &col);
|
||||||
query_order_by_intermediate order_by(const column &col);
|
query_order_by_intermediate order_by(const column &col);
|
||||||
@@ -150,12 +150,21 @@ public:
|
|||||||
|
|
||||||
class query_join_intermediate;
|
class query_join_intermediate;
|
||||||
|
|
||||||
class query_on_intermediate : public query_select_finish
|
struct join_data
|
||||||
|
{
|
||||||
|
table join_table;
|
||||||
|
std::unique_ptr<basic_condition> condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class query_from_intermediate : public query_select
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_select_finish::query_select_finish;
|
using query_select::query_select;
|
||||||
|
|
||||||
query_join_intermediate join_left(const table &t);
|
query_join_intermediate join_left(const table &t);
|
||||||
|
query_from_intermediate join_left(join_data &data);
|
||||||
|
query_from_intermediate join_left(std::vector<join_data> &data_vector);
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition>
|
||||||
query_where_intermediate where(const Condition &cond)
|
query_where_intermediate where(const Condition &cond)
|
||||||
{
|
{
|
||||||
@@ -172,6 +181,8 @@ private:
|
|||||||
query_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
|
query_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using query_on_intermediate = query_from_intermediate;
|
||||||
|
|
||||||
class query_join_intermediate : public query_intermediate
|
class query_join_intermediate : public query_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -191,31 +202,13 @@ private:
|
|||||||
query_on_intermediate on_clause(std::unique_ptr<basic_condition> &&cond);
|
query_on_intermediate on_clause(std::unique_ptr<basic_condition> &&cond);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_from_intermediate : public query_select_finish
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using query_select_finish::query_select_finish;
|
|
||||||
|
|
||||||
query_join_intermediate join_left(const table &t);
|
|
||||||
template<class Condition>
|
|
||||||
query_where_intermediate where(const Condition &cond)
|
|
||||||
{
|
|
||||||
return where_clause(std::make_unique<Condition>(std::move(cond)));
|
|
||||||
}
|
|
||||||
query_group_by_intermediate group_by(const column &col);
|
|
||||||
query_order_by_intermediate order_by(const column &col);
|
|
||||||
|
|
||||||
private:
|
|
||||||
query_where_intermediate where_clause(std::unique_ptr<basic_condition> &&cond);
|
|
||||||
};
|
|
||||||
|
|
||||||
class query_start_intermediate : public basic_query_intermediate
|
class query_start_intermediate : public basic_query_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit query_start_intermediate(connection &db, const sql::schema &schema);
|
explicit query_start_intermediate(connection &db, const sql::schema &schema);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
query_data data_;
|
std::shared_ptr<query_data> data_ { std::make_shared<query_data>() };
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_select_intermediate : public query_start_intermediate
|
class query_select_intermediate : public query_start_intermediate
|
||||||
@@ -240,16 +233,16 @@ class query_into_intermediate : public query_intermediate
|
|||||||
public:
|
public:
|
||||||
using query_intermediate::query_intermediate;
|
using query_intermediate::query_intermediate;
|
||||||
|
|
||||||
query_execute_finish values(std::initializer_list<any_type> values);
|
query_execute values(std::initializer_list<any_type> values);
|
||||||
query_execute_finish values(std::vector<any_type> &&values);
|
query_execute values(std::vector<any_type> &&values);
|
||||||
template<class Type>
|
template<class Type>
|
||||||
query_execute_finish values()
|
query_execute values()
|
||||||
{
|
{
|
||||||
Type obj;
|
Type obj;
|
||||||
return values(std::move(as_placeholder(obj)));
|
return values(std::move(as_placeholder(obj)));
|
||||||
}
|
}
|
||||||
template<class Type>
|
template<class Type>
|
||||||
query_execute_finish values(const Type &obj)
|
query_execute values(const Type &obj)
|
||||||
{
|
{
|
||||||
return values(std::move(value_extractor::extract(obj)));
|
return values(std::move(value_extractor::extract(obj)));
|
||||||
}
|
}
|
||||||
@@ -260,10 +253,10 @@ class query_create_intermediate : public query_start_intermediate
|
|||||||
public:
|
public:
|
||||||
explicit query_create_intermediate(connection &db, const sql::schema &schema);
|
explicit query_create_intermediate(connection &db, const sql::schema &schema);
|
||||||
|
|
||||||
query_execute_finish table(const sql::table &table, std::initializer_list<column_definition> columns);
|
query_execute table(const sql::table &table, std::initializer_list<column_definition> columns);
|
||||||
query_execute_finish table(const sql::table &table, const std::vector<column_definition> &columns);
|
query_execute table(const sql::table &table, const std::vector<column_definition> &columns);
|
||||||
template<class Type>
|
template<class Type>
|
||||||
query_execute_finish table(const sql::table &table)
|
query_execute table(const sql::table &table)
|
||||||
{
|
{
|
||||||
return this->table(table, column_definition_generator::generate<Type>(schema_));
|
return this->table(table, column_definition_generator::generate<Type>(schema_));
|
||||||
}
|
}
|
||||||
@@ -274,7 +267,7 @@ class query_drop_intermediate : query_start_intermediate
|
|||||||
public:
|
public:
|
||||||
explicit query_drop_intermediate(connection &db, const sql::schema &schema);
|
explicit query_drop_intermediate(connection &db, const sql::schema &schema);
|
||||||
|
|
||||||
query_execute_finish table(const sql::table &table);
|
query_execute table(const sql::table &table);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_insert_intermediate : public query_start_intermediate
|
class query_insert_intermediate : public query_start_intermediate
|
||||||
@@ -287,18 +280,18 @@ public:
|
|||||||
query_into_intermediate into(const sql::table &table);
|
query_into_intermediate into(const sql::table &table);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_execute_where_intermediate : public query_execute_finish
|
class query_execute_where_intermediate : public query_execute
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_execute_finish::query_execute_finish;
|
using query_execute::query_execute;
|
||||||
|
|
||||||
query_order_by_intermediate order_by(const column &col);
|
query_order_by_intermediate order_by(const column &col);
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_set_intermediate : public query_execute_finish
|
class query_set_intermediate : public query_execute
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_execute_finish::query_execute_finish;
|
using query_execute::query_execute;
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition>
|
||||||
query_execute_where_intermediate where(const Condition &cond)
|
query_execute_where_intermediate where(const Condition &cond)
|
||||||
@@ -324,10 +317,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class query_delete_from_intermediate : public query_execute_finish
|
class query_delete_from_intermediate : public query_execute
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using query_execute_finish::query_execute_finish;
|
using query_execute::query_execute;
|
||||||
|
|
||||||
template<class Condition>
|
template<class Condition>
|
||||||
query_execute_where_intermediate where(const Condition &cond)
|
query_execute_where_intermediate where(const Condition &cond)
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
class value;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
class pk_reader
|
class pk_reader
|
||||||
{
|
{
|
||||||
@@ -74,7 +76,7 @@ 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_attribute(const char *id, value &val, const utils::field_attributes &attr = utils::null_attributes);
|
||||||
|
|
||||||
template < class Pointer >
|
template < class Pointer >
|
||||||
void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr)
|
void on_belongs_to(const char * /*id*/, Pointer &x, const utils::foreign_attributes &attr)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
class value;
|
||||||
|
|
||||||
class query_result_reader
|
class query_result_reader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -34,7 +36,7 @@ public:
|
|||||||
virtual void read_value(const char *id, size_t index, std::string &value);
|
virtual void read_value(const char *id, size_t index, std::string &value);
|
||||||
virtual void read_value(const char *id, size_t index, std::string &value, size_t s);
|
virtual void read_value(const char *id, size_t index, std::string &value, size_t s);
|
||||||
virtual void read_value(const char *id, size_t index, utils::blob &value);
|
virtual void read_value(const char *id, size_t index, utils::blob &value);
|
||||||
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size);
|
virtual void read_value(const char *id, size_t index, value &val, size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ struct column;
|
|||||||
class record
|
class record
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
using field_by_index = std::vector<field>;
|
using field_ref = std::reference_wrapper<field>;
|
||||||
using field_index_pair = std::pair<std::reference_wrapper<field>, field_by_index::difference_type>;
|
using field_by_index = std::vector<field_ref>;
|
||||||
|
using field_index_pair = std::pair<field, field_by_index::difference_type>;
|
||||||
using field_by_name_map = std::unordered_map<std::string, field_index_pair>;
|
using field_by_name_map = std::unordered_map<std::string, field_index_pair>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -36,13 +37,13 @@ public:
|
|||||||
void process(Operator &op)
|
void process(Operator &op)
|
||||||
{
|
{
|
||||||
for(auto &f : fields_) {
|
for(auto &f : fields_) {
|
||||||
f.process(op);
|
f.get().process(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(field col);
|
void append(const field &col);
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<field>& columns() const;
|
[[nodiscard]] const std::vector<field_ref>& columns() const;
|
||||||
|
|
||||||
[[nodiscard]] const field& at(const column &col) const;
|
[[nodiscard]] const field& at(const column &col) const;
|
||||||
[[nodiscard]] const field& at(size_t index) const;
|
[[nodiscard]] const field& at(size_t index) const;
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] std::string name() const;
|
[[nodiscard]] std::string name() const;
|
||||||
|
|
||||||
|
void create(connection &c);
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
const table_info& attach(const std::string &table_name)
|
const table_info& attach(const std::string &table_name)
|
||||||
{
|
{
|
||||||
|
|||||||
+63
-113
@@ -4,6 +4,7 @@
|
|||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
#include "matador/sql/connection_pool.hpp"
|
#include "matador/sql/connection_pool.hpp"
|
||||||
#include "matador/sql/entity.hpp"
|
#include "matador/sql/entity.hpp"
|
||||||
|
#include "matador/sql/entity_query_builder.hpp"
|
||||||
#include "matador/sql/statement.hpp"
|
#include "matador/sql/statement.hpp"
|
||||||
#include "matador/sql/schema.hpp"
|
#include "matador/sql/schema.hpp"
|
||||||
|
|
||||||
@@ -13,100 +14,14 @@ namespace matador::sql {
|
|||||||
|
|
||||||
class dialect;
|
class dialect;
|
||||||
|
|
||||||
struct join_data
|
enum class session_error {
|
||||||
{
|
Ok = 0,
|
||||||
table join_table;
|
NoConnectionAvailable,
|
||||||
std::unique_ptr<basic_condition> condition;
|
UnknownType,
|
||||||
|
FailedToBuildQuery,
|
||||||
|
FailedToFindObject
|
||||||
};
|
};
|
||||||
|
|
||||||
//class join_collector
|
|
||||||
//{
|
|
||||||
//private:
|
|
||||||
// explicit join_collector(const sql::schema &ts, std::vector<join_data> &joins)
|
|
||||||
// : table_schema_(ts)
|
|
||||||
// , joins_(joins) {}
|
|
||||||
//
|
|
||||||
//public:
|
|
||||||
// template < class Type >
|
|
||||||
// static std::vector<join_data> collect(const sql::schema &ts)
|
|
||||||
// {
|
|
||||||
// const auto info = ts.info<Type>();
|
|
||||||
// if (!info) {
|
|
||||||
// return {};
|
|
||||||
// }
|
|
||||||
// std::vector<join_data> joins;
|
|
||||||
// join_collector collector(ts, joins);
|
|
||||||
// Type obj;
|
|
||||||
// matador::utils::access::process(collector, obj);
|
|
||||||
// return joins;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// template < class PrimaryKeyType >
|
|
||||||
// void on_primary_key(const char *id, PrimaryKeyType &, typename std::enable_if<std::is_integral<PrimaryKeyType>::value && !std::is_same<bool, PrimaryKeyType>::value>::type* = 0) {}
|
|
||||||
// void on_primary_key(const char *id, std::string &, size_t) {}
|
|
||||||
// void on_revision(const char *id, unsigned long long &/*rev*/) {}
|
|
||||||
// template<typename Type>
|
|
||||||
// void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
|
||||||
//
|
|
||||||
// template<class Pointer>
|
|
||||||
// void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr)
|
|
||||||
// {
|
|
||||||
// if (attr.fetch() == utils::fetch_type::LAZY) {
|
|
||||||
// push(id);
|
|
||||||
// } else {
|
|
||||||
// const auto info = table_schema_.info<typename Pointer::value_type>();
|
|
||||||
// if (!info) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// table_name_stack_.push(info.value().name);
|
|
||||||
// typename Pointer::value_type obj;
|
|
||||||
// matador::utils::access::process(*this, obj);
|
|
||||||
// table_name_stack_.pop();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// template<class Pointer>
|
|
||||||
// void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr)
|
|
||||||
// {
|
|
||||||
// if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
|
|
||||||
// push(id);
|
|
||||||
// } else {
|
|
||||||
// const auto info = table_schema_.info<typename Pointer::value_type>();
|
|
||||||
// if (!info) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// table_name_stack_.push(info.value().name);
|
|
||||||
// typename Pointer::value_type obj;
|
|
||||||
// matador::utils::access::process(*this, obj);
|
|
||||||
// table_name_stack_.pop();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// template<class ContainerType>
|
|
||||||
// void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &attr)
|
|
||||||
// {
|
|
||||||
// if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// const auto info = table_schema_.info<typename ContainerType::value_type::value_type>();
|
|
||||||
// if (!info) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// table_name_stack_.push(info.value().name);
|
|
||||||
// typename ContainerType::value_type::value_type obj;
|
|
||||||
// matador::utils::access::process(*this, obj);
|
|
||||||
// table_name_stack_.pop();
|
|
||||||
// }
|
|
||||||
// template<class ContainerType>
|
|
||||||
// void on_has_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
|
|
||||||
// {
|
|
||||||
// on_has_many(id, c, "", "", attr);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//private:
|
|
||||||
// const sql::schema &table_schema_;
|
|
||||||
// std::vector<join_data> &joins_;
|
|
||||||
//};
|
|
||||||
|
|
||||||
class session
|
class session
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -126,33 +41,68 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type, typename PrimaryKeyType>
|
template<typename Type, typename PrimaryKeyType>
|
||||||
entity<Type> find(const PrimaryKeyType &pk) {
|
utils::result<entity<Type>, session_error> find(const PrimaryKeyType &pk) {
|
||||||
auto c = pool_.acquire();
|
auto c = pool_.acquire();
|
||||||
if (!c.valid()) {
|
if (!c.valid()) {
|
||||||
throw std::logic_error("no database connection available");
|
return utils::error(session_error::NoConnectionAvailable);
|
||||||
}
|
}
|
||||||
// collect all columns
|
|
||||||
// - evaluate fetch::Eager flag for relations
|
|
||||||
auto info = schema_->info<Type>();
|
auto info = schema_->info<Type>();
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return {};
|
return utils::error(session_error::UnknownType);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto columns = sql::column_generator::generate<Type>(*schema_);
|
entity_query_builder eqb(*schema_);
|
||||||
|
auto data = eqb.build<Type>(pk);
|
||||||
|
if (!data.is_ok()) {
|
||||||
|
return utils::error(session_error::FailedToBuildQuery);
|
||||||
|
}
|
||||||
|
|
||||||
// auto joins = sql
|
auto obj = build_select_query(c, data.release()).template fetch_one<Type>();
|
||||||
c->query(*schema_).select({}).from(info->name);
|
|
||||||
// build pk where condition
|
|
||||||
// - check if type has pk
|
|
||||||
// - check type
|
|
||||||
// pk_condition_builder<Type> builder;
|
|
||||||
// auto cond = builder.build(pk);
|
|
||||||
|
|
||||||
// create query with relations as requested
|
if (!obj) {
|
||||||
//
|
return utils::error(session_error::FailedToFindObject);
|
||||||
// c->query(*schema_).select<Type>().from("xyz").where().fetch_all();
|
}
|
||||||
|
return utils::ok(entity<Type>{ obj.release() });
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
template<typename Type>
|
||||||
|
utils::result<query_result<Type>, session_error> find() {
|
||||||
|
auto c = pool_.acquire();
|
||||||
|
if (!c.valid()) {
|
||||||
|
return utils::error(session_error::NoConnectionAvailable);
|
||||||
|
}
|
||||||
|
auto info = schema_->info<Type>();
|
||||||
|
if (!info) {
|
||||||
|
return utils::error(session_error::UnknownType);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_query_builder eqb(*schema_);
|
||||||
|
auto data = eqb.build<Type>();
|
||||||
|
if (!data.is_ok()) {
|
||||||
|
return utils::error(session_error::FailedToBuildQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::ok(build_select_query(c, data.release()).template fetch_all<Type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
utils::result<query_from_intermediate, session_error> select() {
|
||||||
|
auto c = pool_.acquire();
|
||||||
|
if (!c.valid()) {
|
||||||
|
return utils::error(session_error::NoConnectionAvailable);
|
||||||
|
}
|
||||||
|
auto info = schema_->info<Type>();
|
||||||
|
if (!info) {
|
||||||
|
return utils::error(session_error::UnknownType);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_query_builder eqb(*schema_);
|
||||||
|
auto data = eqb.build<Type>();
|
||||||
|
if (!data.is_ok()) {
|
||||||
|
return utils::error(session_error::FailedToBuildQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::ok(build_select_query(c, data.release()).template fetch_all<Type>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
@@ -167,15 +117,15 @@ public:
|
|||||||
std::vector<sql::column_definition> describe_table(const std::string &table_name) const;
|
std::vector<sql::column_definition> describe_table(const std::string &table_name) const;
|
||||||
bool table_exists(const std::string &table_name) const;
|
bool table_exists(const std::string &table_name) const;
|
||||||
|
|
||||||
[[nodiscard]] const schema& tables() const;
|
|
||||||
|
|
||||||
const class dialect& dialect() const;
|
const class dialect& dialect() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class query_select_finish;
|
friend class query_select;
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
|
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
|
||||||
|
|
||||||
|
query_select build_select_query(connection_ptr<connection> &conn, entity_query_data &&data) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection_pool<connection> &pool_;
|
connection_pool<connection> &pool_;
|
||||||
const class dialect &dialect_;
|
const class dialect &dialect_;
|
||||||
@@ -200,7 +150,7 @@ entity<Type> session::insert(Type *obj)
|
|||||||
}
|
}
|
||||||
c->query(*schema_)
|
c->query(*schema_)
|
||||||
.insert()
|
.insert()
|
||||||
.into(info->name, column_generator::generate<Type>(*schema_))
|
.into(info->name, column_generator::generate<Type>(*schema_, true))
|
||||||
.values(*obj)
|
.values(*obj)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,22 @@ struct table
|
|||||||
table(const char *name, std::string as = "") // NOLINT(*-explicit-constructor)
|
table(const char *name, std::string as = "") // NOLINT(*-explicit-constructor)
|
||||||
: name(name), alias(std::move(as)) {}
|
: name(name), alias(std::move(as)) {}
|
||||||
table(std::string name, std::string as = "") // NOLINT(*-explicit-constructor)
|
table(std::string name, std::string as = "") // NOLINT(*-explicit-constructor)
|
||||||
: name(std::move(name)), alias(std::move(as)) {}
|
: name(std::move(name))
|
||||||
|
, alias(std::move(as)) {}
|
||||||
|
table(std::string name, std::string as, const std::vector<column> &columns)
|
||||||
|
: name(std::move(name))
|
||||||
|
, alias(std::move(as))
|
||||||
|
, columns(columns) {}
|
||||||
|
|
||||||
table& as(const std::string &a) {
|
table& as(const std::string &a) {
|
||||||
alias = a;
|
alias = a;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] table as(const std::string &a) const {
|
||||||
|
return { name, a, columns };
|
||||||
|
}
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string alias;
|
std::string alias;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#ifndef QUERY_VALUE_HPP
|
||||||
|
#define QUERY_VALUE_HPP
|
||||||
|
|
||||||
|
#include "matador/sql/any_type.hpp"
|
||||||
|
#include "matador/sql/any_type_to_visitor.hpp"
|
||||||
|
#include "matador/sql/data_type_traits.hpp"
|
||||||
|
|
||||||
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename Type>
|
||||||
|
size_t determine_size(const Type &/*val*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t determine_size(const std::string &val);
|
||||||
|
size_t determine_size(const char *val);
|
||||||
|
size_t determine_size(const utils::blob &val);
|
||||||
|
|
||||||
|
}
|
||||||
|
class value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
value() = default;
|
||||||
|
template<typename Type>
|
||||||
|
explicit value(Type value, size_t size = 0)
|
||||||
|
: size_(size)
|
||||||
|
, value_(value)
|
||||||
|
, type_(data_type_traits<Type>::builtin_type(size)) {}
|
||||||
|
explicit value(data_type_t data_type, size_t size = 0);
|
||||||
|
value(const value &x) = default;
|
||||||
|
value& operator=(const value &x) = default;
|
||||||
|
template<typename Type>
|
||||||
|
value& operator=(Type val)
|
||||||
|
{
|
||||||
|
value_ = val;
|
||||||
|
size_ = detail::determine_size(val);
|
||||||
|
type_ = data_type_traits<Type>::builtin_type(size_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
value(value &&x) noexcept;
|
||||||
|
value& operator=(value &&x) noexcept;
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
std::optional<Type> as() const
|
||||||
|
{
|
||||||
|
if (std::holds_alternative<Type>(value_)) {
|
||||||
|
return std::get<Type>(value_);
|
||||||
|
} else {
|
||||||
|
any_type_to_visitor<Type> visitor;
|
||||||
|
std::visit(visitor, const_cast<any_type &>(value_));
|
||||||
|
return visitor.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[[nodiscard]] std::string str() const;
|
||||||
|
|
||||||
|
[[nodiscard]] size_t size() const;
|
||||||
|
[[nodiscard]] data_type_t type() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_integer() const;
|
||||||
|
[[nodiscard]] bool is_floating_point() const;
|
||||||
|
[[nodiscard]] bool is_bool() const;
|
||||||
|
[[nodiscard]] bool is_string() const;
|
||||||
|
[[nodiscard]] bool is_varchar() const;
|
||||||
|
[[nodiscard]] bool is_blob() const;
|
||||||
|
[[nodiscard]] bool is_null() const;
|
||||||
|
[[nodiscard]] bool is_unknown() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
any_type value_;
|
||||||
|
size_t size_{};
|
||||||
|
data_type_t type_{data_type_t::type_unknown};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //QUERY_VALUE_HPP
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
#ifndef QUERY_RESULT_HPP
|
||||||
|
#define QUERY_RESULT_HPP
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
|
||||||
|
template < typename ValueType, typename ErrorType >
|
||||||
|
class [[nodiscard]] result;
|
||||||
|
|
||||||
|
template <typename ValueType>
|
||||||
|
struct is_result : std::false_type {};
|
||||||
|
|
||||||
|
template < typename ValueType, typename ErrorType >
|
||||||
|
struct is_result<result<ValueType, ErrorType>> : std::true_type {};
|
||||||
|
|
||||||
|
template < typename ValueType >
|
||||||
|
class ok
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = ValueType;
|
||||||
|
explicit constexpr ok(const ValueType &value) : value_(value) {}
|
||||||
|
explicit constexpr ok(ValueType &&value) : value_(std::move(value)) {}
|
||||||
|
|
||||||
|
constexpr ValueType&& release() { return std::move(value_); }
|
||||||
|
const ValueType& value() const { return value_; }
|
||||||
|
ValueType& value() { return value_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueType value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename ErrorType >
|
||||||
|
class error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = ErrorType;
|
||||||
|
|
||||||
|
explicit constexpr error(const ErrorType &error) : error_(error) {}
|
||||||
|
explicit constexpr error(ErrorType &&error) : error_(std::move(error)) {}
|
||||||
|
|
||||||
|
constexpr ErrorType&& release() { return std::move(error_); }
|
||||||
|
const ErrorType& value() const { return error_; }
|
||||||
|
ErrorType value() { return error_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ErrorType error_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename ValueType, typename ErrorType >
|
||||||
|
class result
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = ok<ValueType>;
|
||||||
|
using error_type = error<ErrorType>;
|
||||||
|
|
||||||
|
result() : result_(ValueType{}) {}
|
||||||
|
result(value_type value) : result_(std::move(value)) {} // NOLINT(*-explicit-constructor)
|
||||||
|
result(error_type error) : result_(std::move(error)) {} // NOLINT(*-explicit-constructor)
|
||||||
|
result(const result<ValueType, ErrorType> &x) = default;
|
||||||
|
result& operator=(const result<ValueType, ErrorType> &x) = default;
|
||||||
|
result(result<ValueType, ErrorType> &&x) = default;
|
||||||
|
result& operator=(result<ValueType, ErrorType> &&x) = default;
|
||||||
|
|
||||||
|
operator bool() const { return is_ok(); } // NOLINT(*-explicit-constructor)
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_ok() const { return std::holds_alternative<value_type>(result_); }
|
||||||
|
[[nodiscard]] bool is_error() const { return std::holds_alternative<error_type>(result_); }
|
||||||
|
|
||||||
|
ValueType&& release() { return std::get<value_type>(result_).release(); }
|
||||||
|
ErrorType&& release_error() { return std::get<error_type>(result_).release(); }
|
||||||
|
|
||||||
|
const ValueType& value() const { return std::get<value_type>(result_).value(); }
|
||||||
|
const ErrorType& err() const { return std::get<error_type>(result_).value(); }
|
||||||
|
ErrorType err() { return std::get<error_type>(result_).value(); }
|
||||||
|
|
||||||
|
constexpr const ValueType* operator->() const { return &value(); }
|
||||||
|
constexpr ValueType* operator->() { return &std::get<value_type>(result_).value(); }
|
||||||
|
|
||||||
|
template<typename Func, typename SecondValueType = typename std::invoke_result_t<Func, ValueType >>
|
||||||
|
result<SecondValueType, ErrorType> transform(Func &&f) {
|
||||||
|
if (is_ok()) {
|
||||||
|
return result<SecondValueType, ErrorType>(ok(f(release())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result<SecondValueType, ErrorType>(error(release_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func, typename SecondValueType = typename std::invoke_result_t<Func, ValueType >::value_type::value_type>
|
||||||
|
result<SecondValueType, ErrorType> and_then(Func &&f) {
|
||||||
|
if (is_ok()) {
|
||||||
|
return f(release());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result<SecondValueType, ErrorType>(error(release_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func, typename SecondErrorType = typename std::invoke_result_t<Func, ErrorType >::error_type::value_type>
|
||||||
|
result<ValueType, SecondErrorType> or_else(Func &&f) {
|
||||||
|
if (is_error()) {
|
||||||
|
return f(err());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result<ValueType, SecondErrorType>(ok(release()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<value_type, error_type> result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_RESULT_HPP
|
||||||
+4
-22
@@ -37,6 +37,8 @@ set(SQL_SOURCES
|
|||||||
sql/any_type_to_string_visitor.cpp
|
sql/any_type_to_string_visitor.cpp
|
||||||
sql/field.cpp
|
sql/field.cpp
|
||||||
sql/table_definition.cpp
|
sql/table_definition.cpp
|
||||||
|
sql/value.cpp
|
||||||
|
sql/entity_query_builder.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SQL_HEADER
|
set(SQL_HEADER
|
||||||
@@ -92,28 +94,7 @@ set(SQL_HEADER
|
|||||||
../include/matador/sql/entity_query_builder.hpp
|
../include/matador/sql/entity_query_builder.hpp
|
||||||
../include/matador/sql/table_definition.hpp
|
../include/matador/sql/table_definition.hpp
|
||||||
../include/matador/sql/has_many_to_many_relation.hpp
|
../include/matador/sql/has_many_to_many_relation.hpp
|
||||||
)
|
../include/matador/sql/value.hpp
|
||||||
|
|
||||||
set(QUERY_SOURCES
|
|
||||||
query/query.cpp
|
|
||||||
query/query_compiler.cpp
|
|
||||||
query/query_parts.cpp
|
|
||||||
query/column.cpp
|
|
||||||
query/query_builder.cpp
|
|
||||||
query/query_intermediates.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(QUERY_HEADER
|
|
||||||
../include/matador/query/query.hpp
|
|
||||||
../include/matador/query/query_part_visitor.hpp
|
|
||||||
../include/matador/query/query_compiler.hpp
|
|
||||||
../include/matador/query/query_parts.hpp
|
|
||||||
../include/matador/query/column.hpp
|
|
||||||
../include/matador/query/query_builder.hpp
|
|
||||||
../include/matador/query/query_intermediates.hpp
|
|
||||||
../include/matador/query/sql_commands.hpp
|
|
||||||
../include/matador/query/query_data.hpp
|
|
||||||
../include/matador/query/table.hpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(UTILS_HEADER
|
set(UTILS_HEADER
|
||||||
@@ -130,6 +111,7 @@ set(UTILS_HEADER
|
|||||||
../include/matador/utils/types.hpp
|
../include/matador/utils/types.hpp
|
||||||
../include/matador/utils/foreign_attributes.hpp
|
../include/matador/utils/foreign_attributes.hpp
|
||||||
../include/matador/utils/fetch_type.hpp
|
../include/matador/utils/fetch_type.hpp
|
||||||
|
../include/matador/utils/result.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(UTILS_SOURCES
|
set(UTILS_SOURCES
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#include "matador/query/column.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
column::column(const char *name)
|
|
||||||
: name(name) {}
|
|
||||||
|
|
||||||
column::column(std::string name)
|
|
||||||
: name(std::move(name)) {}
|
|
||||||
|
|
||||||
column::column(std::string table_name, std::string name, std::string as)
|
|
||||||
: table(std::move(table_name))
|
|
||||||
, name(std::move(name))
|
|
||||||
, alias(std::move(as)) {}
|
|
||||||
|
|
||||||
column& column::as(std::string a) {
|
|
||||||
alias = std::move(a);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#include "matador/query/query.hpp"
|
|
||||||
|
|
||||||
namespace matador::sql {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#include "matador/query/query_builder.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
query_builder::query_builder(const std::shared_ptr<sql::schema> &scm)
|
|
||||||
: schema_(scm) {}
|
|
||||||
|
|
||||||
query_select_intermediate query_builder::select(std::initializer_list<column> columns)
|
|
||||||
{
|
|
||||||
return query_select_intermediate{schema_};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#include "matador/query/query_compiler.hpp"
|
|
||||||
#include "matador/query/query_data.hpp"
|
|
||||||
#include "matador/query/column.hpp"
|
|
||||||
|
|
||||||
#include "matador/sql/dialect.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
query_compiler::query_compiler(sql::dialect &d)
|
|
||||||
: dialect_(d)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string query_compiler::compile(const query_data *data)
|
|
||||||
{
|
|
||||||
sql_.clear();
|
|
||||||
for (const auto &part : data->parts) {
|
|
||||||
part->accept(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sql_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void query_compiler::visit(query_select_part &select_part)
|
|
||||||
{
|
|
||||||
auto ci = "name"_col.as("c01");
|
|
||||||
}
|
|
||||||
|
|
||||||
void query_compiler::visit(query_from_part &from_part)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include "matador/query/query_intermediates.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
query_intermediate::query_intermediate(const std::shared_ptr<sql::schema> &scm)
|
|
||||||
: schema_(scm) {}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#include "matador/query/query_parts.hpp"
|
|
||||||
|
|
||||||
namespace matador::query {
|
|
||||||
|
|
||||||
query_part::query_part(sql::dialect::token_t token)
|
|
||||||
: token_(token) {}
|
|
||||||
|
|
||||||
query_select_part::query_select_part(std::vector<column> columns)
|
|
||||||
: query_part(sql::dialect::token_t::SELECT)
|
|
||||||
, columns_(std::move(columns)) {}
|
|
||||||
|
|
||||||
void query_select_part::accept(query_part_visitor &visitor)
|
|
||||||
{
|
|
||||||
visitor.visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
query_from_part::query_from_part(std::string table_name)
|
|
||||||
: query_part(sql::dialect::token_t::FROM)
|
|
||||||
, table_(std::move(table_name)) {}
|
|
||||||
|
|
||||||
query_from_part::query_from_part(std::string table_name, std::string as)
|
|
||||||
: query_part(sql::dialect::token_t::FROM)
|
|
||||||
, table_(std::move(table_name))
|
|
||||||
, alias_(std::move(as)) {}
|
|
||||||
|
|
||||||
void query_from_part::accept(query_part_visitor &visitor)
|
|
||||||
{
|
|
||||||
visitor.visit(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "matador/sql/noop_connection.hpp"
|
#include "matador/sql/noop_connection.hpp"
|
||||||
#include "matador/sql/dialect_builder.hpp"
|
#include "matador/sql/dialect_builder.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ void column_definition::type(data_type_t type)
|
|||||||
|
|
||||||
std::string column_definition::str() const
|
std::string column_definition::str() const
|
||||||
{
|
{
|
||||||
|
if (std::holds_alternative<std::string>(value_)) {
|
||||||
|
return std::get<std::string>(value_);
|
||||||
|
}
|
||||||
|
|
||||||
any_type_to_visitor<std::string> visitor;
|
any_type_to_visitor<std::string> visitor;
|
||||||
std::visit(visitor, const_cast<any_type &>(value_));
|
std::visit(visitor, const_cast<any_type &>(value_));
|
||||||
return visitor.result;
|
return visitor.result;
|
||||||
|
|||||||
+20
-2
@@ -1,5 +1,7 @@
|
|||||||
#include "matador/sql/condition.hpp"
|
#include "matador/sql/condition.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/query_intermediates.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
condition<column, placeholder, std::enable_if<true>::type>::condition(const column &fld, basic_condition::operand_t op, const placeholder &val)
|
condition<column, placeholder, std::enable_if<true>::type>::condition(const column &fld, basic_condition::operand_t op, const placeholder &val)
|
||||||
@@ -12,17 +14,33 @@ std::string condition<column, placeholder, std::enable_if<true>::type>::evaluate
|
|||||||
return d.prepare_identifier(field_) + " " + operand + " " + d.next_placeholder(query.bind_vars);
|
return d.prepare_identifier(field_) + " " + operand + " " + d.next_placeholder(query.bind_vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
condition<column, query_context>::condition(column col, basic_condition::operand_t op, query_context &q)
|
condition<column, query_context>::condition(column col, basic_condition::operand_t op, const query_context &q)
|
||||||
: basic_column_condition(std::move(col), op), query_(q)
|
: basic_column_condition(std::move(col), op), query_(q)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string condition<column, query_context>::evaluate(const dialect &d, query_context &query) const
|
std::string condition<column, query_context>::evaluate(const dialect &d, query_context &query) const
|
||||||
{
|
{
|
||||||
std::string result(d.prepare_identifier(field_) + " " + operand + " (");
|
std::string result(d.prepare_identifier(field_) + " " + operand + " (");
|
||||||
result += (")");
|
result += query_.sql + (")");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition<column, query_context> in( const column& col, const query_context &q ) {
|
||||||
|
return {col, basic_condition::operand_t::IN_LIST, q};
|
||||||
|
}
|
||||||
|
|
||||||
|
condition<column, query_context> in( const column& col, const query_select& q ) {
|
||||||
|
return in(col, q.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
condition<column, std::string> like( const column& col, const std::string& val ) {
|
||||||
|
return {col, basic_condition::operand_t::LIKE, val};
|
||||||
|
}
|
||||||
|
|
||||||
|
condition<column, query_context> equals( const column& col, query_context& q ) {
|
||||||
|
return {col, basic_condition::operand_t::EQUAL, q};
|
||||||
|
}
|
||||||
|
|
||||||
condition<column, column> operator==(const column &a, const column &b)
|
condition<column, column> operator==(const column &a, const column &b)
|
||||||
{
|
{
|
||||||
return {a, basic_condition::operand_t::EQUAL, b};
|
return {a, basic_condition::operand_t::EQUAL, b};
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ size_t connection::execute(const std::string &sql) const
|
|||||||
return connection_->execute(sql);
|
return connection_->execute(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
sql::query connection::query(const sql::schema &schema) const
|
sql::query connection::query(const schema &schema) const
|
||||||
{
|
{
|
||||||
return sql::query(*const_cast<connection*>(this), schema);
|
return sql::query(*const_cast<connection*>(this), schema);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,21 @@
|
|||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
void data_type_traits<nullptr_t>::read_value(query_result_reader &reader, const char *id, size_t index, nullptr_t &/*value*/)
|
||||||
|
{
|
||||||
|
// reader.read_value(id, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void data_type_traits<nullptr_t>::bind_value(parameter_binder &binder, size_t index, nullptr_t &/*value*/)
|
||||||
|
{
|
||||||
|
// binder.bind(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void data_type_traits<nullptr_t>::bind_result_value(result_parameter_binder &binder, size_t index, nullptr_t &/*value*/)
|
||||||
|
{
|
||||||
|
// binder.bind_result_value(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
void data_type_traits<char>::read_value(query_result_reader &reader, const char *id, size_t index, char &value)
|
void data_type_traits<char>::read_value(query_result_reader &reader, const char *id, size_t index, char &value)
|
||||||
{
|
{
|
||||||
reader.read_value(id, index, value);
|
reader.read_value(id, index, value);
|
||||||
|
|||||||
+3
-3
@@ -37,7 +37,7 @@ std::string dialect::prepare_identifier_string(const std::string &col) const
|
|||||||
|
|
||||||
for (auto &part : parts) {
|
for (auto &part : parts) {
|
||||||
escape_quotes_in_identifier(part);
|
escape_quotes_in_identifier(part);
|
||||||
// quote_identifier(part);
|
quote_identifier(part);
|
||||||
}
|
}
|
||||||
return utils::join(parts, ".");
|
return utils::join(parts, ".");
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,8 @@ std::string dialect::prepare_literal(const std::string &str) const
|
|||||||
|
|
||||||
void dialect::quote_identifier(std::string &str) const
|
void dialect::quote_identifier(std::string &str) const
|
||||||
{
|
{
|
||||||
str.insert(0, token_at(token_t::START_QUOTE));
|
// str.insert(0, token_at(token_t::START_QUOTE));
|
||||||
str += token_at(token_t::END_QUOTE);
|
// str += token_at(token_t::END_QUOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dialect::escape_quotes_in_identifier(std::string &str) const
|
void dialect::escape_quotes_in_identifier(std::string &str) const
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include "matador/sql/entity_query_builder.hpp"
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
void entity_query_builder::on_primary_key(const char *id, std::string &, size_t)
|
||||||
|
{
|
||||||
|
push(id);
|
||||||
|
if (!is_root_entity()) {
|
||||||
|
auto b = pk_.is_varchar();
|
||||||
|
std::cout << "is matching primary key: " << std::boolalpha << b << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_query_builder::on_revision(const char *id, unsigned long long &/*rev*/)
|
||||||
|
{
|
||||||
|
push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_query_builder::push(const std::string &column_name)
|
||||||
|
{
|
||||||
|
char str[4];
|
||||||
|
snprintf(str, 4, "c%02d", ++column_index);
|
||||||
|
entity_query_data_.columns.emplace_back(table_info_stack_.top().name, column_name, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool entity_query_builder::is_root_entity() const {
|
||||||
|
return table_info_stack_.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_query_builder::append_join(const column &left, const column &right)
|
||||||
|
{
|
||||||
|
entity_query_data_.joins.push_back({
|
||||||
|
{ right.table },
|
||||||
|
make_condition(left == right)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+10
-16
@@ -7,24 +7,20 @@ namespace matador::sql {
|
|||||||
field::field(std::string name)
|
field::field(std::string name)
|
||||||
: name_(std::move(name))
|
: name_(std::move(name))
|
||||||
, value_(nullptr)
|
, value_(nullptr)
|
||||||
, type_(data_type_t::type_unknown)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
field::field(std::string name, data_type_t data_type, size_t size, int index)
|
field::field(std::string name, data_type_t data_type, size_t size, int index)
|
||||||
: name_(std::move(name))
|
: name_(std::move(name))
|
||||||
, size_(size)
|
|
||||||
, index_(index)
|
, index_(index)
|
||||||
, type_(data_type) {}
|
, value_(data_type, size) {}
|
||||||
|
|
||||||
field::field(field &&x) noexcept
|
field::field(field &&x) noexcept
|
||||||
: name_(std::move(x.name_))
|
: name_(std::move(x.name_))
|
||||||
, index_(x.index_)
|
, index_(x.index_)
|
||||||
, value_(std::move(x.value_))
|
, value_(std::move(x.value_))
|
||||||
, type_(x.type_)
|
|
||||||
{
|
{
|
||||||
x.value_ = nullptr;
|
x.value_ = nullptr;
|
||||||
x.index_ = -1;
|
x.index_ = -1;
|
||||||
x.type_ = data_type_t::type_unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
field &field::operator=(field &&x) noexcept
|
field &field::operator=(field &&x) noexcept
|
||||||
@@ -32,10 +28,8 @@ field &field::operator=(field &&x) noexcept
|
|||||||
name_ = std::move(x.name_);
|
name_ = std::move(x.name_);
|
||||||
index_ = x.index_;
|
index_ = x.index_;
|
||||||
value_ = std::move(x.value_);
|
value_ = std::move(x.value_);
|
||||||
type_ = x.type_;
|
|
||||||
x.index_ = -1;
|
x.index_ = -1;
|
||||||
x.value_ = nullptr;
|
x.value_ = nullptr;
|
||||||
x.type_ = data_type_t::type_unknown;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -47,7 +41,7 @@ const std::string &field::name() const
|
|||||||
|
|
||||||
size_t field::size() const
|
size_t field::size() const
|
||||||
{
|
{
|
||||||
return size_;
|
return value_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int field::index() const
|
int field::index() const
|
||||||
@@ -68,42 +62,42 @@ std::string field::str() const
|
|||||||
|
|
||||||
bool field::is_integer() const
|
bool field::is_integer() const
|
||||||
{
|
{
|
||||||
return type_ >= data_type_t::type_char && type_ <= data_type_t::type_unsigned_long_long;
|
return value_.is_integer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_floating_point() const
|
bool field::is_floating_point() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_float || type_ == data_type_t::type_double;
|
return value_.is_floating_point();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_bool() const
|
bool field::is_bool() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_bool;
|
return value_.is_bool();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_string() const
|
bool field::is_string() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_text;
|
return value_.is_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_varchar() const
|
bool field::is_varchar() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_varchar;
|
return value_.is_varchar();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_blob() const
|
bool field::is_blob() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_blob;
|
return value_.is_blob();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_null() const
|
bool field::is_null() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_null;
|
return value_.is_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field::is_unknown() const
|
bool field::is_unknown() const
|
||||||
{
|
{
|
||||||
return type_ == data_type_t::type_unknown;
|
return value_.is_unknown();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ void query_compiler::visit(query_select_part &select_part)
|
|||||||
void query_compiler::visit(query_from_part &from_part)
|
void query_compiler::visit(query_from_part &from_part)
|
||||||
{
|
{
|
||||||
query_.table = from_part.table();
|
query_.table = from_part.table();
|
||||||
if (dialect_.default_schema_name().empty()) {
|
if (!dialect_.default_schema_name().empty()) {
|
||||||
query_.sql += " " + dialect_.token_at(dialect::token_t::FROM) +
|
query_.sql += " " + dialect_.token_at(dialect::token_t::FROM) +
|
||||||
" " + dialect_.prepare_identifier(from_part.table().name) +
|
" " + dialect_.prepare_identifier(from_part.table().name) +
|
||||||
(from_part.table().alias.empty() ? "" : " AS " +
|
(from_part.table().alias.empty() ? "" : " AS " +
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ basic_query_intermediate::basic_query_intermediate(connection &db, const sql::sc
|
|||||||
: connection_(db)
|
: connection_(db)
|
||||||
, schema_(schema) {}
|
, schema_(schema) {}
|
||||||
|
|
||||||
query_result<record> query_select_finish::fetch_all()
|
query_result<record> query_select::fetch_all()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return connection_.fetch(compiler.compile(&data_));
|
return connection_.fetch(compiler.compile(data_.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<record> query_select_finish::fetch_one()
|
std::optional<record> query_select::fetch_one()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
auto result = connection_.fetch(compiler.compile(&data_));
|
auto result = connection_.fetch(compiler.compile(data_.get()));
|
||||||
auto first = result.begin();
|
auto first = result.begin();
|
||||||
if (first == result.end()) {
|
if (first == result.end()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -26,145 +26,139 @@ std::optional<record> query_select_finish::fetch_one()
|
|||||||
return *first.get();
|
return *first.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
query_context query_select_finish::build() const
|
query_context query_select::build() const
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return compiler.compile(&data_);
|
return compiler.compile(data_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<query_result_impl> query_select_finish::fetch()
|
std::unique_ptr<query_result_impl> query_select::fetch()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return connection_.fetch(compiler.compile(&data_).sql);
|
return connection_.fetch(compiler.compile(data_.get()).sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
statement query_select_finish::prepare()
|
statement query_select::prepare()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return connection_.prepare(compiler.compile(&data_));
|
return connection_.prepare(compiler.compile(data_.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
query_intermediate::query_intermediate(connection &db, const sql::schema &schema, query_data &data)
|
query_intermediate::query_intermediate(connection &db, const sql::schema &schema, const std::shared_ptr<query_data> &data)
|
||||||
: basic_query_intermediate(db, schema), data_(data) {}
|
: basic_query_intermediate(db, schema), data_(data) {}
|
||||||
|
|
||||||
query_offset_intermediate query_limit_intermediate::offset(size_t offset)
|
query_offset_intermediate query_limit_intermediate::offset(size_t offset)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_offset_part>(offset));
|
data_->parts.push_back(std::make_unique<query_offset_part>(offset));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_limit_intermediate query_offset_intermediate::limit(size_t limit)
|
query_limit_intermediate query_offset_intermediate::limit(size_t limit)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_limit_part>(limit));
|
data_->parts.push_back(std::make_unique<query_limit_part>(limit));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_limit_intermediate query_order_direction_intermediate::limit(size_t limit)
|
query_limit_intermediate query_order_direction_intermediate::limit(size_t limit)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_limit_part>(limit));
|
data_->parts.push_back(std::make_unique<query_limit_part>(limit));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_by_intermediate query_group_by_intermediate::order_by(const column &col)
|
query_order_by_intermediate query_group_by_intermediate::order_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_order_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_direction_intermediate query_order_by_intermediate::asc()
|
query_order_direction_intermediate query_order_by_intermediate::asc()
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_asc_part>());
|
data_->parts.push_back(std::make_unique<query_order_by_asc_part>());
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_direction_intermediate query_order_by_intermediate::desc()
|
query_order_direction_intermediate query_order_by_intermediate::desc()
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_desc_part>());
|
data_->parts.push_back(std::make_unique<query_order_by_desc_part>());
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_where_intermediate query_from_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
query_where_intermediate query_from_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
if (cond) {
|
||||||
|
data_->parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
||||||
|
}
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_group_by_intermediate query_from_intermediate::group_by(const column &col)
|
query_group_by_intermediate query_from_intermediate::group_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_group_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_group_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_by_intermediate query_from_intermediate::order_by(const column &col)
|
query_order_by_intermediate query_from_intermediate::order_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_order_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_group_by_intermediate query_where_intermediate::group_by(const column &col)
|
query_group_by_intermediate query_where_intermediate::group_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_group_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_group_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_by_intermediate query_where_intermediate::order_by(const column &col)
|
query_order_by_intermediate query_where_intermediate::order_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_order_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
|
||||||
}
|
|
||||||
|
|
||||||
query_join_intermediate query_on_intermediate::join_left(const table &t)
|
|
||||||
{
|
|
||||||
data_.parts.push_back(std::make_unique<query_join_part>(t));
|
|
||||||
return {connection_, schema_, data_};
|
|
||||||
}
|
|
||||||
|
|
||||||
query_where_intermediate query_on_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
|
||||||
{
|
|
||||||
data_.parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
|
||||||
return {connection_, schema_, data_};
|
|
||||||
}
|
|
||||||
|
|
||||||
query_group_by_intermediate query_on_intermediate::group_by(const column &col)
|
|
||||||
{
|
|
||||||
data_.parts.push_back(std::make_unique<query_group_by_part>(col));
|
|
||||||
return {connection_, schema_, data_};
|
|
||||||
}
|
|
||||||
|
|
||||||
query_order_by_intermediate query_on_intermediate::order_by(const column &col)
|
|
||||||
{
|
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_part>(col));
|
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_on_intermediate query_join_intermediate::on_clause(std::unique_ptr<basic_condition> &&cond)
|
query_on_intermediate query_join_intermediate::on_clause(std::unique_ptr<basic_condition> &&cond)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_on_part>(std::move(cond)));
|
data_->parts.push_back(std::make_unique<query_on_part>(std::move(cond)));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_join_intermediate query_from_intermediate::join_left(const table &t)
|
query_join_intermediate query_from_intermediate::join_left(const table &t)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_join_part>(t));
|
data_->parts.push_back(std::make_unique<query_join_part>(t));
|
||||||
|
return {connection_, schema_, data_};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_from_intermediate query_from_intermediate::join_left(join_data &data)
|
||||||
|
{
|
||||||
|
data_->parts.push_back(std::make_unique<query_join_part>(data.join_table));
|
||||||
|
data_->parts.push_back(std::make_unique<query_on_part>(std::move(data.condition)));
|
||||||
|
return {connection_, schema_, data_};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_from_intermediate query_from_intermediate::join_left(std::vector<join_data> &data_vector)
|
||||||
|
{
|
||||||
|
for (auto &data : data_vector) {
|
||||||
|
data_->parts.push_back(std::make_unique<query_join_part>(data.join_table));
|
||||||
|
data_->parts.push_back(std::make_unique<query_on_part>(std::move(data.condition)));
|
||||||
|
}
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_select_intermediate::query_select_intermediate(connection &db, const sql::schema &schema, const std::vector<column>& columns)
|
query_select_intermediate::query_select_intermediate(connection &db, const sql::schema &schema, const std::vector<column>& columns)
|
||||||
: query_start_intermediate(db, schema)
|
: query_start_intermediate(db, schema)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_select_part>(columns));
|
data_->parts.push_back(std::make_unique<query_select_part>(columns));
|
||||||
}
|
}
|
||||||
|
|
||||||
query_from_intermediate query_select_intermediate::from(const table& t)
|
query_from_intermediate query_select_intermediate::from(const table& t)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_from_part>(t));
|
data_->parts.push_back(std::make_unique<query_from_part>(t));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_insert_intermediate::query_insert_intermediate(connection &db, const sql::schema &schema)
|
query_insert_intermediate::query_insert_intermediate(connection &db, const sql::schema &schema)
|
||||||
: query_start_intermediate(db, schema)
|
: query_start_intermediate(db, schema)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_insert_part>());
|
data_->parts.push_back(std::make_unique<query_insert_part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
query_into_intermediate query_insert_intermediate::into(const sql::table &table, std::initializer_list<column> column_names)
|
query_into_intermediate query_insert_intermediate::into(const sql::table &table, std::initializer_list<column> column_names)
|
||||||
@@ -174,89 +168,89 @@ query_into_intermediate query_insert_intermediate::into(const sql::table &table,
|
|||||||
|
|
||||||
query_into_intermediate query_insert_intermediate::into(const table &table, std::vector<column> &&column_names)
|
query_into_intermediate query_insert_intermediate::into(const table &table, std::vector<column> &&column_names)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_into_part>(table, column_names));
|
data_->parts.push_back(std::make_unique<query_into_part>(table, column_names));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_into_intermediate query_insert_intermediate::into(const table &table)
|
query_into_intermediate query_insert_intermediate::into(const table &table)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_into_part>(table, table.columns));
|
data_->parts.push_back(std::make_unique<query_into_part>(table, table.columns));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t query_execute_finish::execute()
|
size_t query_execute::execute()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return connection_.execute(compiler.compile(&data_).sql);
|
return connection_.execute(compiler.compile(data_.get()).sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
statement query_execute_finish::prepare()
|
statement query_execute::prepare()
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return connection_.prepare(compiler.compile(&data_));
|
return connection_.prepare(compiler.compile(data_.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
query_context query_execute_finish::build() const
|
query_context query_execute::build() const
|
||||||
{
|
{
|
||||||
query_compiler compiler(connection_.dialect());
|
query_compiler compiler(connection_.dialect());
|
||||||
return compiler.compile(&data_);
|
return compiler.compile(data_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_finish query_into_intermediate::values(std::initializer_list<any_type> values)
|
query_execute query_into_intermediate::values(std::initializer_list<any_type> values)
|
||||||
{
|
{
|
||||||
return this->values(std::vector<any_type>(values));
|
return this->values(std::vector<any_type>(values));
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_finish query_into_intermediate::values(std::vector<any_type> &&values)
|
query_execute query_into_intermediate::values(std::vector<any_type> &&values)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_values_part>(std::move(values)));
|
data_->parts.push_back(std::make_unique<query_values_part>(std::move(values)));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_create_intermediate::query_create_intermediate(connection &db, const sql::schema &schema)
|
query_create_intermediate::query_create_intermediate(connection &db, const sql::schema &schema)
|
||||||
: query_start_intermediate(db, schema) {
|
: query_start_intermediate(db, schema) {
|
||||||
data_.parts.push_back(std::make_unique<query_create_part>());
|
data_->parts.push_back(std::make_unique<query_create_part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_finish query_create_intermediate::table(const sql::table &table, std::initializer_list<column_definition> columns)
|
query_execute query_create_intermediate::table(const sql::table &table, std::initializer_list<column_definition> columns)
|
||||||
{
|
{
|
||||||
return this->table(table, std::vector<column_definition>{columns});
|
return this->table(table, std::vector<column_definition>{columns});
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_finish query_create_intermediate::table(const sql::table &table, const std::vector<column_definition> &columns)
|
query_execute query_create_intermediate::table(const sql::table &table, const std::vector<column_definition> &columns)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_create_table_part>(table, columns));
|
data_->parts.push_back(std::make_unique<query_create_table_part>(table, columns));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_drop_intermediate::query_drop_intermediate(connection &db, const sql::schema &schema)
|
query_drop_intermediate::query_drop_intermediate(connection &db, const sql::schema &schema)
|
||||||
: query_start_intermediate(db, schema)
|
: query_start_intermediate(db, schema)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_drop_part>());
|
data_->parts.push_back(std::make_unique<query_drop_part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_finish query_drop_intermediate::table(const sql::table &table)
|
query_execute query_drop_intermediate::table(const sql::table &table)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_drop_table_part>(table));
|
data_->parts.push_back(std::make_unique<query_drop_table_part>(table));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_order_by_intermediate query_execute_where_intermediate::order_by(const column &col)
|
query_order_by_intermediate query_execute_where_intermediate::order_by(const column &col)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_order_by_part>(col));
|
data_->parts.push_back(std::make_unique<query_order_by_part>(col));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_where_intermediate query_set_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
query_execute_where_intermediate query_set_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
data_->parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_update_intermediate::query_update_intermediate(connection &db, const sql::schema &schema, const sql::table& table)
|
query_update_intermediate::query_update_intermediate(connection &db, const sql::schema &schema, const sql::table& table)
|
||||||
: query_start_intermediate(db, schema)
|
: query_start_intermediate(db, schema)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_update_part>(table));
|
data_->parts.push_back(std::make_unique<query_update_part>(table));
|
||||||
}
|
}
|
||||||
|
|
||||||
query_set_intermediate query_update_intermediate::set(std::initializer_list<key_value_pair> columns)
|
query_set_intermediate query_update_intermediate::set(std::initializer_list<key_value_pair> columns)
|
||||||
@@ -266,26 +260,26 @@ query_set_intermediate query_update_intermediate::set(std::initializer_list<key_
|
|||||||
|
|
||||||
query_set_intermediate query_update_intermediate::set(std::vector<key_value_pair> &&columns)
|
query_set_intermediate query_update_intermediate::set(std::vector<key_value_pair> &&columns)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_set_part>(std::move(columns)));
|
data_->parts.push_back(std::make_unique<query_set_part>(std::move(columns)));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query_execute_where_intermediate query_delete_from_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
query_execute_where_intermediate query_delete_from_intermediate::where_clause(std::unique_ptr<basic_condition> &&cond)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
data_->parts.push_back(std::make_unique<query_where_part>(std::move(cond)));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_delete_intermediate::query_delete_intermediate(connection &db, const sql::schema &schema)
|
query_delete_intermediate::query_delete_intermediate(connection &db, const sql::schema &schema)
|
||||||
: query_start_intermediate(db, schema)
|
: query_start_intermediate(db, schema)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_delete_part>());
|
data_->parts.push_back(std::make_unique<query_delete_part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
query_delete_from_intermediate query_delete_intermediate::from(const sql::table &table)
|
query_delete_from_intermediate query_delete_intermediate::from(const sql::table &table)
|
||||||
{
|
{
|
||||||
data_.parts.push_back(std::make_unique<query_delete_from_part>(table));
|
data_->parts.push_back(std::make_unique<query_delete_from_part>(table));
|
||||||
return {connection_, schema_, data_};
|
return {connection_, schema_, data_};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "matador/sql/query_result_impl.hpp"
|
#include "matador/sql/query_result_impl.hpp"
|
||||||
#include "matador/sql/query_result_reader.hpp"
|
#include "matador/sql/query_result_reader.hpp"
|
||||||
|
#include "matador/sql/value.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
@@ -39,9 +40,9 @@ void query_result_impl::on_attribute(const char *id, std::string &value, const u
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
query_result_impl::on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr)
|
query_result_impl::on_attribute(const char *id, value &val, const utils::field_attributes &attr)
|
||||||
{
|
{
|
||||||
reader_->read_value(id, column_index_++, value, type, attr.size());
|
reader_->read_value(id, column_index_++, val, attr.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<column_definition>& query_result_impl::prototype() const
|
const std::vector<column_definition>& query_result_impl::prototype() const
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "matador/sql/query_result_reader.hpp"
|
#include "matador/sql/query_result_reader.hpp"
|
||||||
#include "matador/sql/to_value.hpp"
|
#include "matador/sql/to_value.hpp"
|
||||||
|
#include "matador/sql/value.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
@@ -104,82 +105,82 @@ void query_result_reader::read_value(const char *id, size_t index, utils::blob &
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
void convert(const char *valstr, sql::any_type &value)
|
void convert(const char *valstr, value &val)
|
||||||
{
|
{
|
||||||
Type val{};
|
Type local_val{};
|
||||||
sql::to_value(val, valstr);
|
sql::to_value(local_val, valstr);
|
||||||
value = val;
|
val = local_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void query_result_reader::read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size)
|
void query_result_reader::read_value(const char *id, size_t index, value &val, size_t size)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (val.type()) {
|
||||||
case sql::data_type_t::type_char:
|
case sql::data_type_t::type_char:
|
||||||
convert<char>(column(index), value);
|
convert<char>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_short:
|
case sql::data_type_t::type_short:
|
||||||
convert<short>(column(index), value);
|
convert<short>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_int:
|
case sql::data_type_t::type_int:
|
||||||
convert<int>(column(index), value);
|
convert<int>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_long:
|
case sql::data_type_t::type_long:
|
||||||
convert<long>(column(index), value);
|
convert<long>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_long_long:
|
case sql::data_type_t::type_long_long:
|
||||||
convert<long long>(column(index), value);
|
convert<long long>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_unsigned_char:
|
case sql::data_type_t::type_unsigned_char:
|
||||||
convert<unsigned char>(column(index), value);
|
convert<unsigned char>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_unsigned_short:
|
case sql::data_type_t::type_unsigned_short:
|
||||||
convert<unsigned short>(column(index), value);
|
convert<unsigned short>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_unsigned_int:
|
case sql::data_type_t::type_unsigned_int:
|
||||||
convert<unsigned int>(column(index), value);
|
convert<unsigned int>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_unsigned_long:
|
case sql::data_type_t::type_unsigned_long:
|
||||||
convert<unsigned long>(column(index), value);
|
convert<unsigned long>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_unsigned_long_long:
|
case sql::data_type_t::type_unsigned_long_long:
|
||||||
convert<unsigned long long>(column(index), value);
|
convert<unsigned long long>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_float:
|
case sql::data_type_t::type_float:
|
||||||
convert<float>(column(index), value);
|
convert<float>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_double:
|
case sql::data_type_t::type_double:
|
||||||
convert<double>(column(index), value);
|
convert<double>(column(index), val);
|
||||||
break;
|
break;
|
||||||
case sql::data_type_t::type_bool: {
|
case sql::data_type_t::type_bool: {
|
||||||
int val{};
|
int local_val{};
|
||||||
sql::to_value(val, column(index));
|
sql::to_value(local_val, column(index));
|
||||||
value = val > 0;
|
val = local_val > 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_text:
|
case sql::data_type_t::type_text:
|
||||||
case sql::data_type_t::type_varchar: {
|
case sql::data_type_t::type_varchar: {
|
||||||
value = std::string{column(index)};
|
val = std::string{column(index)};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_char_pointer: {
|
case sql::data_type_t::type_char_pointer: {
|
||||||
value = column(index);
|
val = column(index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_time:
|
case sql::data_type_t::type_time:
|
||||||
case sql::data_type_t::type_date: {
|
case sql::data_type_t::type_date: {
|
||||||
value = std::string{column(index)};
|
val = std::string{column(index)};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_null: {
|
case sql::data_type_t::type_null: {
|
||||||
value = nullptr_t{};
|
val = nullptr_t{};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_blob: {
|
case sql::data_type_t::type_blob: {
|
||||||
value = utils::blob{};
|
val = utils::blob{};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_unknown: {
|
case sql::data_type_t::type_unknown: {
|
||||||
value = std::string(column(index));
|
val = std::string(column(index));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-16
@@ -7,23 +7,27 @@
|
|||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
record::record(std::initializer_list<field> columns)
|
record::record(std::initializer_list<field> columns)
|
||||||
: fields_(columns)
|
|
||||||
{
|
{
|
||||||
init();
|
for (auto &&col :columns) {
|
||||||
|
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||||
|
fields_.push_back(std::ref(it.first->second.first));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record::record(const std::vector<field> &columns)
|
record::record(const std::vector<field> &columns)
|
||||||
: fields_(columns)
|
|
||||||
{
|
{
|
||||||
init();
|
for (auto &&col :columns) {
|
||||||
|
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||||
|
fields_.push_back(std::ref(it.first->second.first));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record::record(const record &x)
|
record::record(const record &x)
|
||||||
: fields_(x.fields_)
|
: fields_by_name_(x.fields_by_name_)
|
||||||
//, pk_index_(x.pk_index_)
|
//, pk_index_(x.pk_index_)
|
||||||
{
|
{
|
||||||
for (auto& col : fields_) {
|
for (auto& col : fields_by_name_) {
|
||||||
add_to_map(col, col.index());
|
fields_.push_back(std::ref(col.second.first));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,16 +37,16 @@ record &record::operator=(const record &x)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
fields_ = x.fields_;
|
fields_by_name_ = x.fields_by_name_;
|
||||||
fields_by_name_.clear();
|
fields_.clear();
|
||||||
// pk_index_ = x.pk_index_;
|
// pk_index_ = x.pk_index_;
|
||||||
for (auto& col : fields_) {
|
for (auto& col : fields_by_name_) {
|
||||||
add_to_map(col, col.index());
|
fields_.push_back(std::ref(col.second.first));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<field> &record::columns() const
|
const std::vector<record::field_ref> &record::columns() const
|
||||||
{
|
{
|
||||||
return fields_;
|
return fields_;
|
||||||
}
|
}
|
||||||
@@ -63,7 +67,9 @@ const std::vector<field> &record::columns() const
|
|||||||
|
|
||||||
const field &record::at(const column &col) const
|
const field &record::at(const column &col) const
|
||||||
{
|
{
|
||||||
return fields_by_name_.at(col.name).first;
|
const auto &res = fields_by_name_.at(col.name);
|
||||||
|
const auto &f = res.first;
|
||||||
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field &record::at(size_t index) const
|
const field &record::at(size_t index) const
|
||||||
@@ -82,10 +88,10 @@ record::const_iterator record::find(const std::string &column_name) const {
|
|||||||
return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
|
return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void record::append(field col)
|
void record::append(const field &col)
|
||||||
{
|
{
|
||||||
auto &ref = fields_.emplace_back(std::move(col));
|
const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
|
||||||
add_to_map(ref, fields_.size() - 1);
|
fields_.push_back(std::ref(it.first->second.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
record::iterator record::begin()
|
record::iterator record::begin()
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ namespace matador::sql {
|
|||||||
schema::schema(std::string name)
|
schema::schema(std::string name)
|
||||||
: name_(std::move(name)) {}
|
: name_(std::move(name)) {}
|
||||||
|
|
||||||
|
void schema::create(connection &c) {
|
||||||
|
for (const auto &ti : repository_) {
|
||||||
|
// ti.second.prototype
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string schema::name() const
|
std::string schema::name() const
|
||||||
{
|
{
|
||||||
return name_;
|
return name_;
|
||||||
|
|||||||
+11
-5
@@ -89,11 +89,6 @@ bool session::table_exists(const std::string &table_name) const
|
|||||||
return c->exists(dialect_.default_schema_name(), table_name);
|
return c->exists(dialect_.default_schema_name(), table_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema& session::tables() const
|
|
||||||
{
|
|
||||||
return *schema_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const class dialect &session::dialect() const
|
const class dialect &session::dialect() const
|
||||||
{
|
{
|
||||||
return dialect_;
|
return dialect_;
|
||||||
@@ -108,4 +103,15 @@ std::unique_ptr<query_result_impl> session::fetch(const std::string &sql) const
|
|||||||
return c->fetch(sql);
|
return c->fetch(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query_select session::build_select_query(connection_ptr<connection> &conn, entity_query_data &&data) const
|
||||||
|
{
|
||||||
|
return conn->query(*schema_)
|
||||||
|
.select(data.columns)
|
||||||
|
.from(data.root_table_name)
|
||||||
|
.join_left(data.joins)
|
||||||
|
.where(std::move(data.where_clause))
|
||||||
|
.order_by({data.root_table_name, data.pk_column_})
|
||||||
|
.asc();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
#include "matador/sql/value.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
size_t determine_size(const std::string &val)
|
||||||
|
{
|
||||||
|
return val.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t determine_size(const char *val)
|
||||||
|
{
|
||||||
|
return strlen(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t determine_size(const utils::blob &val)
|
||||||
|
{
|
||||||
|
return val.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
value::value(data_type_t data_type, size_t size)
|
||||||
|
: size_(size)
|
||||||
|
, type_(data_type) {}
|
||||||
|
|
||||||
|
value::value(value &&x) noexcept
|
||||||
|
: value_(std::move(x.value_))
|
||||||
|
, type_(x.type_)
|
||||||
|
{
|
||||||
|
x.value_ = nullptr;
|
||||||
|
x.type_ = data_type_t::type_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
value &value::operator=(value &&x) noexcept
|
||||||
|
{
|
||||||
|
value_ = std::move(x.value_);
|
||||||
|
type_ = x.type_;
|
||||||
|
x.value_ = nullptr;
|
||||||
|
x.type_ = data_type_t::type_unknown;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value::str() const
|
||||||
|
{
|
||||||
|
return as<std::string>().value();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t value::size() const
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_type_t value::type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_integer() const
|
||||||
|
{
|
||||||
|
return type_ >= data_type_t::type_char && type_ <= data_type_t::type_unsigned_long_long;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_floating_point() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_float || type_ == data_type_t::type_double;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_bool() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_string() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_varchar() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_varchar || type_ == data_type_t::type_char_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_blob() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_null() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool value::is_unknown() const
|
||||||
|
{
|
||||||
|
return type_ == data_type_t::type_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+8
-5
@@ -3,7 +3,7 @@ Include(FetchContent)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.4.0 # or a later release
|
GIT_TAG v3.5.4 # or a later release
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
@@ -19,7 +19,7 @@ add_executable(tests
|
|||||||
BackendProviderTest.cpp
|
BackendProviderTest.cpp
|
||||||
models/product.hpp
|
models/product.hpp
|
||||||
models/order.hpp
|
models/order.hpp
|
||||||
models/order_details.h
|
models/order_details.hpp
|
||||||
ColumnDefinitionGeneratorTest.cpp
|
ColumnDefinitionGeneratorTest.cpp
|
||||||
ColumnGeneratorTest.cpp
|
ColumnGeneratorTest.cpp
|
||||||
ValueGeneratorTest.cpp
|
ValueGeneratorTest.cpp
|
||||||
@@ -34,13 +34,16 @@ add_executable(tests
|
|||||||
models/location.hpp
|
models/location.hpp
|
||||||
models/optional.hpp
|
models/optional.hpp
|
||||||
ConvertTest.cpp
|
ConvertTest.cpp
|
||||||
DummyConnection.hpp
|
|
||||||
DummyConnection.cpp
|
|
||||||
EntityQueryBuilderTest.cpp
|
EntityQueryBuilderTest.cpp
|
||||||
models/author.hpp
|
models/author.hpp
|
||||||
models/book.hpp
|
models/book.hpp
|
||||||
FieldTest.cpp
|
FieldTest.cpp
|
||||||
models/recipe.hpp)
|
models/recipe.hpp
|
||||||
|
ValueTest.cpp
|
||||||
|
ResultTest.cpp
|
||||||
|
utils/auto_reset_event.hpp
|
||||||
|
utils/auto_reset_event.cpp
|
||||||
|
models/student.hpp)
|
||||||
|
|
||||||
target_link_libraries(tests PRIVATE
|
target_link_libraries(tests PRIVATE
|
||||||
Catch2::Catch2WithMain
|
Catch2::Catch2WithMain
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador::utils;
|
using namespace matador::utils;
|
||||||
|
|
||||||
TEST_CASE("Generate columns from object", "[column generator]") {
|
TEST_CASE("Generate column definitions from object", "[column][definition][generator]") {
|
||||||
schema repo("main");
|
schema repo("main");
|
||||||
|
|
||||||
auto columns = column_definition_generator::generate<matador::test::product>(repo);
|
auto columns = column_definition_generator::generate<matador::test::product>(repo);
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include <matador/sql/connection_pool.hpp>
|
#include "matador/sql/connection_pool.hpp"
|
||||||
|
#include "matador/sql/noop_connection.hpp"
|
||||||
|
|
||||||
#include "DummyConnection.hpp"
|
#include "utils/auto_reset_event.hpp"
|
||||||
|
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
|
using namespace matador::test::utils;
|
||||||
|
|
||||||
TEST_CASE("Create connection pool", "[connection pool]") {
|
TEST_CASE("Create connection pool", "[connection pool]") {
|
||||||
using pool_t = connection_pool<matador::test::DummyConnection>;
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
pool_t pool("sqlite://sqlite.db", 4);
|
pool_t pool("noop://noop.db", 4);
|
||||||
|
|
||||||
REQUIRE(pool.size() == 4);
|
REQUIRE(pool.size() == 4);
|
||||||
REQUIRE(pool.idle() == 4);
|
REQUIRE(pool.idle() == 4);
|
||||||
@@ -51,9 +53,9 @@ TEST_CASE("Create connection pool", "[connection pool]") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Acquire connection by id", "[connection pool]") {
|
TEST_CASE("Acquire connection by id", "[connection pool]") {
|
||||||
using pool_t = connection_pool<matador::test::DummyConnection>;
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
pool_t pool("sqlite://sqlite.db", 4);
|
pool_t pool("noop://noop.db", 4);
|
||||||
|
|
||||||
REQUIRE(pool.size() == 4);
|
REQUIRE(pool.size() == 4);
|
||||||
REQUIRE(pool.idle() == 4);
|
REQUIRE(pool.idle() == 4);
|
||||||
@@ -79,3 +81,74 @@ TEST_CASE("Acquire connection by id", "[connection pool]") {
|
|||||||
REQUIRE(same_ptr.valid());
|
REQUIRE(same_ptr.valid());
|
||||||
REQUIRE(same_ptr.id() == connection_id);
|
REQUIRE(same_ptr.id() == connection_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Try acquire connection", "[connection pool][try acquire]") {
|
||||||
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
|
pool_t pool("noop://noop.db", 1);
|
||||||
|
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 1);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
auto ptr = pool.try_acquire();
|
||||||
|
REQUIRE(ptr.valid());
|
||||||
|
REQUIRE(ptr.id());
|
||||||
|
REQUIRE(ptr.id().value() > 0);
|
||||||
|
REQUIRE(ptr->is_open());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 0);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
|
||||||
|
auto ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(!ptr2.valid());
|
||||||
|
|
||||||
|
pool.release(ptr);
|
||||||
|
REQUIRE(!ptr.valid());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 1);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(ptr2.valid());
|
||||||
|
REQUIRE(ptr2.id());
|
||||||
|
REQUIRE(ptr2.id().value() > 0);
|
||||||
|
REQUIRE(ptr2->is_open());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 0);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
|
||||||
|
pool.release(ptr2);
|
||||||
|
|
||||||
|
auto_reset_event reset_main_event;
|
||||||
|
auto_reset_event reset_thread_event;
|
||||||
|
|
||||||
|
std::thread t([&reset_main_event, &reset_thread_event, &pool]() {
|
||||||
|
auto c1 = pool.acquire();
|
||||||
|
REQUIRE(c1.valid());
|
||||||
|
REQUIRE(c1.id());
|
||||||
|
REQUIRE(c1.id().value() > 0);
|
||||||
|
|
||||||
|
reset_main_event.set();
|
||||||
|
|
||||||
|
reset_thread_event.wait_one();
|
||||||
|
|
||||||
|
pool.release(c1);
|
||||||
|
REQUIRE(!c1.valid());
|
||||||
|
reset_main_event.set();
|
||||||
|
});
|
||||||
|
reset_main_event.wait_one();
|
||||||
|
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(!ptr2.valid());
|
||||||
|
|
||||||
|
reset_thread_event.set();
|
||||||
|
|
||||||
|
reset_main_event.wait_one();
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(ptr2.valid());
|
||||||
|
REQUIRE(ptr2.id());
|
||||||
|
REQUIRE(ptr2.id().value() > 0);
|
||||||
|
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "DummyConnection.hpp"
|
|
||||||
|
|
||||||
namespace matador::test {
|
|
||||||
|
|
||||||
DummyConnection::DummyConnection(sql::connection_info info)
|
|
||||||
: connection_info_(std::move(info))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DummyConnection::DummyConnection(const std::string &dns)
|
|
||||||
: DummyConnection(sql::connection_info::parse(dns))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void DummyConnection::open()
|
|
||||||
{
|
|
||||||
is_open_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DummyConnection::close()
|
|
||||||
{
|
|
||||||
is_open_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DummyConnection::is_open() const
|
|
||||||
{
|
|
||||||
return is_open_;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#ifndef QUERY_DUMMYCONNECTION_HPP
|
|
||||||
#define QUERY_DUMMYCONNECTION_HPP
|
|
||||||
|
|
||||||
#include "matador/sql/connection_info.hpp"
|
|
||||||
|
|
||||||
namespace matador::test {
|
|
||||||
|
|
||||||
class DummyConnection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DummyConnection(sql::connection_info info);
|
|
||||||
explicit DummyConnection(const std::string& dns);
|
|
||||||
DummyConnection(const DummyConnection &x) = default;
|
|
||||||
DummyConnection& operator=(const DummyConnection &x) = default;
|
|
||||||
DummyConnection(DummyConnection &&x) noexcept = default;
|
|
||||||
DummyConnection& operator=(DummyConnection &&x) noexcept = default;
|
|
||||||
~DummyConnection() = default;
|
|
||||||
|
|
||||||
void open();
|
|
||||||
void close();
|
|
||||||
[[nodiscard]] bool is_open() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
sql::connection_info connection_info_;
|
|
||||||
|
|
||||||
bool is_open_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_DUMMYCONNECTION_HPP
|
|
||||||
+166
-31
@@ -1,35 +1,46 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include <matador/sql/connection.hpp>
|
#include <matador/sql/connection.hpp>
|
||||||
#include <matador/sql/dialect.hpp>
|
|
||||||
#include <matador/sql/entity_query_builder.hpp>
|
#include <matador/sql/entity_query_builder.hpp>
|
||||||
|
|
||||||
|
#include "models/airplane.hpp"
|
||||||
#include "models/author.hpp"
|
#include "models/author.hpp"
|
||||||
#include "models/book.hpp"
|
#include "models/book.hpp"
|
||||||
|
#include "models/flight.hpp"
|
||||||
#include "models/recipe.hpp"
|
#include "models/recipe.hpp"
|
||||||
#include "models/order.hpp"
|
#include "models/order.hpp"
|
||||||
|
#include "models/student.hpp"
|
||||||
|
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
|
|
||||||
TEST_CASE("Create sql query data for entity with eager belongs to", "[query][entity][builder]") {
|
TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") {
|
||||||
using namespace matador::test;
|
using namespace matador::test;
|
||||||
connection db("noop://noop.db");
|
connection db("noop://noop.db");
|
||||||
schema scm("noop");
|
schema scm("noop");
|
||||||
scm.attach<author>("authors");
|
scm.attach<airplane>("airplanes");
|
||||||
scm.attach<book>("books");
|
scm.attach<flight>("flights");
|
||||||
|
|
||||||
entity_query_builder eqb(17, scm);
|
entity_query_builder eqb(scm);
|
||||||
|
|
||||||
auto data = eqb.build<book>();
|
auto data = eqb.build<flight>(17);
|
||||||
|
|
||||||
REQUIRE(data.has_value());
|
REQUIRE(data.is_ok());
|
||||||
REQUIRE(data->root_table_name == "books");
|
REQUIRE(data->root_table_name == "flights");
|
||||||
REQUIRE(data->joins.size() == 1);
|
REQUIRE(data->joins.size() == 1);
|
||||||
REQUIRE(data->columns.size() == 9);
|
const std::vector<column> expected_columns {
|
||||||
REQUIRE(data->where_clause);
|
{ "flights", "id", "c01" },
|
||||||
|
{ "airplanes", "id", "c02" },
|
||||||
|
{ "airplanes", "brand", "c03" },
|
||||||
|
{ "airplanes", "model", "c04" },
|
||||||
|
{ "flights", "pilot_name", "c05" },
|
||||||
|
};
|
||||||
|
REQUIRE(data->columns.size() == expected_columns.size());
|
||||||
|
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||||
|
REQUIRE(expected_columns[i].equals(data->columns[i]));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
||||||
{ "books", "books.author_id = authors.id"}
|
{ "airplanes", R"("flights"."airplane_id" = "airplanes"."id")"}
|
||||||
};
|
};
|
||||||
|
|
||||||
query_context qc;
|
query_context qc;
|
||||||
@@ -40,15 +51,66 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent
|
|||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REQUIRE(data->where_clause);
|
||||||
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
||||||
REQUIRE(cond == "books.id = 17");
|
REQUIRE(cond == R"("flights"."id" = 17)");
|
||||||
|
}
|
||||||
|
|
||||||
auto &jd = data->joins.front();
|
TEST_CASE("Create sql query data for entity with eager belongs to", "[query][entity][builder]") {
|
||||||
|
using namespace matador::test;
|
||||||
|
connection db("noop://noop.db");
|
||||||
|
schema scm("noop");
|
||||||
|
scm.attach<author>("authors");
|
||||||
|
scm.attach<book>("books");
|
||||||
|
|
||||||
auto context = db.query(scm)
|
entity_query_builder eqb(scm);
|
||||||
|
|
||||||
|
auto data = eqb.build<book>(17);
|
||||||
|
|
||||||
|
REQUIRE(data.is_ok());
|
||||||
|
REQUIRE(data->root_table_name == "books");
|
||||||
|
REQUIRE(data->joins.size() == 1);
|
||||||
|
const std::vector<column> expected_columns {
|
||||||
|
{ "books", "id", "c01" },
|
||||||
|
{ "books", "title", "c02" },
|
||||||
|
{ "authors", "id", "c03" },
|
||||||
|
{ "authors", "first_name", "c04" },
|
||||||
|
{ "authors", "last_name", "c05" },
|
||||||
|
{ "authors", "date_of_birth", "c06" },
|
||||||
|
{ "authors", "year_of_birth", "c07" },
|
||||||
|
{ "authors", "distinguished", "c08" },
|
||||||
|
{ "books", "published_in", "c09" }
|
||||||
|
};
|
||||||
|
REQUIRE(data->columns.size() == expected_columns.size());
|
||||||
|
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||||
|
REQUIRE(expected_columns[i].equals(data->columns[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
||||||
|
{ "authors", R"("books"."author_id" = "authors"."id")"}
|
||||||
|
};
|
||||||
|
|
||||||
|
query_context qc;
|
||||||
|
size_t index{0};
|
||||||
|
for (const auto &jd : data->joins) {
|
||||||
|
REQUIRE(jd.join_table.name == expected_join_data[index].first);
|
||||||
|
REQUIRE(jd.condition->evaluate(db.dialect(), qc) == expected_join_data[index].second);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(data->where_clause);
|
||||||
|
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
||||||
|
REQUIRE(cond == R"("books"."id" = 17)");
|
||||||
|
|
||||||
|
auto q = db.query(scm)
|
||||||
.select(data->columns)
|
.select(data->columns)
|
||||||
.from(data->root_table_name)
|
.from(data->root_table_name);
|
||||||
.join_left(jd.join_table).on(std::move(jd.condition))
|
|
||||||
|
for (auto &jd : data->joins) {
|
||||||
|
q.join_left(jd.join_table)
|
||||||
|
.on(std::move(jd.condition));
|
||||||
|
}
|
||||||
|
auto context = q
|
||||||
.where(std::move(data->where_clause))
|
.where(std::move(data->where_clause))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@@ -61,18 +123,37 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
|
|||||||
scm.attach<order_details>("order_details");
|
scm.attach<order_details>("order_details");
|
||||||
scm.attach<order>("orders");
|
scm.attach<order>("orders");
|
||||||
|
|
||||||
entity_query_builder eqb(17, scm);
|
entity_query_builder eqb(scm);
|
||||||
|
|
||||||
auto data = eqb.build<order>();
|
auto data = eqb.build<order>(17);
|
||||||
|
|
||||||
REQUIRE(data.has_value());
|
REQUIRE(data.is_ok());
|
||||||
REQUIRE(data->root_table_name == "orders");
|
REQUIRE(data->root_table_name == "orders");
|
||||||
REQUIRE(data->joins.size() == 1);
|
REQUIRE(data->joins.size() == 1);
|
||||||
REQUIRE(data->columns.size() == 15);
|
const std::vector<column> expected_columns = {
|
||||||
REQUIRE(data->where_clause);
|
{ "orders", "order_id", "c01" },
|
||||||
|
{ "orders", "order_date", "c02" },
|
||||||
|
{ "orders", "required_date", "c03" },
|
||||||
|
{ "orders", "shipped_date", "c04" },
|
||||||
|
{ "orders", "ship_via", "c05" },
|
||||||
|
{ "orders", "freight", "c06" },
|
||||||
|
{ "orders", "ship_name", "c07" },
|
||||||
|
{ "orders", "ship_address", "c08" },
|
||||||
|
{ "orders", "ship_city", "c09" },
|
||||||
|
{ "orders", "ship_region", "c10" },
|
||||||
|
{ "orders", "ship_postal_code", "c11" },
|
||||||
|
{ "orders", "ship_country", "c12" },
|
||||||
|
{ "order_details", "order_details_id", "c13" },
|
||||||
|
{ "order_details", "order_id", "c14" },
|
||||||
|
{ "order_details", "product_id", "c15" }
|
||||||
|
};
|
||||||
|
REQUIRE(data->columns.size() == expected_columns.size());
|
||||||
|
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||||
|
REQUIRE(expected_columns[i].equals(data->columns[i]));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
||||||
{ "orders", "orders.order_id = order_details.order_id"}
|
{ "order_details", R"("orders"."order_id" = "order_details"."order_id")"}
|
||||||
};
|
};
|
||||||
|
|
||||||
query_context qc;
|
query_context qc;
|
||||||
@@ -83,8 +164,9 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
|
|||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REQUIRE(data->where_clause);
|
||||||
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
||||||
REQUIRE(cond == "orders.order_id = 17");
|
REQUIRE(cond == R"("orders"."order_id" = 17)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Create sql query data for entity with eager many to many", "[query][entity][builder]") {
|
TEST_CASE("Create sql query data for entity with eager many to many", "[query][entity][builder]") {
|
||||||
@@ -95,19 +177,27 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e
|
|||||||
scm.attach<ingredient>("ingredients");
|
scm.attach<ingredient>("ingredients");
|
||||||
scm.attach<recipe_ingredient>("recipe_ingredients");
|
scm.attach<recipe_ingredient>("recipe_ingredients");
|
||||||
|
|
||||||
entity_query_builder eqb(17, scm);
|
entity_query_builder eqb(scm);
|
||||||
|
|
||||||
auto data = eqb.build<ingredient>();
|
auto data = eqb.build<ingredient>(17);
|
||||||
|
|
||||||
REQUIRE(data.has_value());
|
REQUIRE(data.is_ok());
|
||||||
REQUIRE(data->root_table_name == "ingredients");
|
REQUIRE(data->root_table_name == "ingredients");
|
||||||
REQUIRE(data->joins.size() == 2);
|
REQUIRE(data->joins.size() == 2);
|
||||||
REQUIRE(data->columns.size() == 4);
|
const std::vector<column> expected_columns {
|
||||||
REQUIRE(data->where_clause);
|
{ "ingredients", "id", "c01" },
|
||||||
|
{ "ingredients", "name", "c02" },
|
||||||
|
{ "recipes", "id", "c03" },
|
||||||
|
{ "recipes", "name", "c04" }
|
||||||
|
};
|
||||||
|
REQUIRE(data->columns.size() == expected_columns.size());
|
||||||
|
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||||
|
REQUIRE(expected_columns[i].equals(data->columns[i]));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
||||||
{ "ingredients", "ingredients.id = recipe_ingredients.ingredient_id"},
|
{ "recipe_ingredients", R"("ingredients"."id" = "recipe_ingredients"."ingredient_id")"},
|
||||||
{ "recipes", "recipes.id = recipe_ingredients.recipe_id"}
|
{ "recipes", R"("recipe_ingredients"."recipe_id" = "recipes"."id")"}
|
||||||
};
|
};
|
||||||
|
|
||||||
query_context qc;
|
query_context qc;
|
||||||
@@ -118,6 +208,51 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e
|
|||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REQUIRE(data->where_clause);
|
||||||
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
||||||
REQUIRE(cond == "ingredients.id = 17");
|
REQUIRE(cond == R"("ingredients"."id" = 17)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Create sql query data for entity with eager many to many (inverse part)", "[query][entity][builder]") {
|
||||||
|
using namespace matador::test;
|
||||||
|
connection db("noop://noop.db");
|
||||||
|
schema scm("noop");
|
||||||
|
scm.attach<student>("students");
|
||||||
|
scm.attach<course>("courses");
|
||||||
|
scm.attach<student_course>("student_courses");
|
||||||
|
|
||||||
|
entity_query_builder eqb(scm);
|
||||||
|
|
||||||
|
auto data = eqb.build<course>(17);
|
||||||
|
|
||||||
|
REQUIRE(data.is_ok());
|
||||||
|
REQUIRE(data->root_table_name == "courses");
|
||||||
|
REQUIRE(data->joins.size() == 2);
|
||||||
|
const std::vector<column> expected_columns {
|
||||||
|
{ "courses", "id", "c01" },
|
||||||
|
{ "courses", "title", "c02" },
|
||||||
|
{ "students", "id", "c03" },
|
||||||
|
{ "students", "name", "c04" }
|
||||||
|
};
|
||||||
|
REQUIRE(data->columns.size() == expected_columns.size());
|
||||||
|
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||||
|
REQUIRE(expected_columns[i].equals(data->columns[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> expected_join_data {
|
||||||
|
{ "student_courses", R"("courses"."id" = "student_courses"."course_id")"},
|
||||||
|
{ "students", R"("student_courses"."student_id" = "students"."id")"}
|
||||||
|
};
|
||||||
|
|
||||||
|
query_context qc;
|
||||||
|
size_t index{0};
|
||||||
|
for (const auto &jd : data->joins) {
|
||||||
|
REQUIRE(jd.join_table.name == expected_join_data[index].first);
|
||||||
|
REQUIRE(jd.condition->evaluate(db.dialect(), qc) == expected_join_data[index].second);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(data->where_clause);
|
||||||
|
auto cond = data->where_clause->evaluate(db.dialect(), qc);
|
||||||
|
REQUIRE(cond == R"("courses"."id" = 17)");
|
||||||
}
|
}
|
||||||
+2
-2
@@ -9,8 +9,8 @@ TEST_CASE("Field test", "[field]") {
|
|||||||
|
|
||||||
REQUIRE(f.name() == "name");
|
REQUIRE(f.name() == "name");
|
||||||
REQUIRE(f.index() == -1);
|
REQUIRE(f.index() == -1);
|
||||||
REQUIRE(f.is_unknown());
|
REQUIRE(!f.is_unknown());
|
||||||
REQUIRE(!f.is_null());
|
REQUIRE(f.is_null());
|
||||||
REQUIRE(!f.is_integer());
|
REQUIRE(!f.is_integer());
|
||||||
REQUIRE(!f.is_floating_point());
|
REQUIRE(!f.is_floating_point());
|
||||||
REQUIRE(!f.is_blob());
|
REQUIRE(!f.is_blob());
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "matador/utils/result.hpp"
|
||||||
|
|
||||||
|
namespace matador::test {
|
||||||
|
|
||||||
|
enum class math_error : int32_t {
|
||||||
|
DIVISION_BY_ZERO = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
utils::result<float, math_error>divide(int x, int y) {
|
||||||
|
if (y == 0) {
|
||||||
|
return utils::error(math_error::DIVISION_BY_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::ok(float(x) / y);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<float, math_error>multiply(int x, int y) {
|
||||||
|
return utils::ok(float(x) * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<float, math_error>plus(int x, int y) {
|
||||||
|
return utils::ok(float(x) + y);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<float, std::string>error_to_string(math_error err) {
|
||||||
|
switch (err) {
|
||||||
|
case math_error::DIVISION_BY_ZERO:
|
||||||
|
return utils::error(std::string("division by zero error"));
|
||||||
|
default:
|
||||||
|
return utils::error(std::string("unknown error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace matador;
|
||||||
|
|
||||||
|
TEST_CASE("Result tests", "[result]") {
|
||||||
|
auto res = test::divide(4, 2);
|
||||||
|
REQUIRE(res);
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
REQUIRE(!res.is_error());
|
||||||
|
|
||||||
|
REQUIRE((res.value() == 2.0));
|
||||||
|
|
||||||
|
REQUIRE_THROWS(res.err());
|
||||||
|
|
||||||
|
res = test::divide(4, 0);
|
||||||
|
REQUIRE(!res);
|
||||||
|
REQUIRE(!res.is_ok());
|
||||||
|
REQUIRE(res.is_error());
|
||||||
|
|
||||||
|
REQUIRE((res.err() == test::math_error::DIVISION_BY_ZERO));
|
||||||
|
|
||||||
|
res = test::divide(4, 2)
|
||||||
|
.and_then([](const auto &val) { return test::multiply(val, 5); })
|
||||||
|
.and_then([](const auto &val) { return test::plus(val, 10); });
|
||||||
|
|
||||||
|
REQUIRE(res);
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
REQUIRE(!res.is_error());
|
||||||
|
REQUIRE((res.value() == 20.0));
|
||||||
|
|
||||||
|
res = test::divide(4, 0)
|
||||||
|
.and_then([](const auto &val) {
|
||||||
|
return test::multiply(val, 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!res);
|
||||||
|
REQUIRE(!res.is_ok());
|
||||||
|
REQUIRE(res.is_error());
|
||||||
|
REQUIRE((res.err() == test::math_error::DIVISION_BY_ZERO));
|
||||||
|
|
||||||
|
auto res2 = test::divide(4, 0)
|
||||||
|
.or_else([](const auto &err) {
|
||||||
|
return test::error_to_string(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!res2);
|
||||||
|
REQUIRE(!res2.is_ok());
|
||||||
|
REQUIRE(res2.is_error());
|
||||||
|
REQUIRE((res2.err() == "division by zero error"));
|
||||||
|
|
||||||
|
res = test::divide(4, 2)
|
||||||
|
.and_then([](const auto &val) { return test::multiply(val, 5); })
|
||||||
|
.transform([](const auto &val) { return val + 10; });
|
||||||
|
|
||||||
|
REQUIRE(res);
|
||||||
|
REQUIRE(res.is_ok());
|
||||||
|
REQUIRE(!res.is_error());
|
||||||
|
REQUIRE((res.value() == 20.0));
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "matador/sql/value.hpp"
|
||||||
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
|
using namespace matador::sql;
|
||||||
|
|
||||||
|
TEST_CASE("Test value class", "[value]") {
|
||||||
|
value v;
|
||||||
|
|
||||||
|
REQUIRE(v.is_unknown());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_unknown);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = 7;
|
||||||
|
|
||||||
|
REQUIRE(v.is_integer());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_int);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
REQUIRE(v.as<int>() == 7);
|
||||||
|
REQUIRE(v.as<long>() == 7);
|
||||||
|
|
||||||
|
v = "test";
|
||||||
|
|
||||||
|
REQUIRE(v.is_varchar());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_char_pointer);
|
||||||
|
REQUIRE(v.size() == 4);
|
||||||
|
|
||||||
|
v = std::string{"hello"};
|
||||||
|
|
||||||
|
REQUIRE(v.is_varchar());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_varchar);
|
||||||
|
REQUIRE(v.size() == 5);
|
||||||
|
|
||||||
|
v = 4.5;
|
||||||
|
|
||||||
|
REQUIRE(v.is_floating_point());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_double);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = 6.7f;
|
||||||
|
|
||||||
|
REQUIRE(v.is_floating_point());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_float);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = std::string();
|
||||||
|
|
||||||
|
REQUIRE(v.is_string());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_text);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = true;
|
||||||
|
|
||||||
|
REQUIRE(v.is_bool());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_bool);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = nullptr;
|
||||||
|
|
||||||
|
REQUIRE(v.is_null());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_null);
|
||||||
|
REQUIRE(v.size() == 0);
|
||||||
|
|
||||||
|
v = matador::utils::blob{ 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
REQUIRE(v.is_blob());
|
||||||
|
REQUIRE(v.type() == data_type_t::type_blob);
|
||||||
|
REQUIRE(v.size() == 4);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef QUERY_ORDER_HPP
|
#ifndef QUERY_ORDER_HPP
|
||||||
#define QUERY_ORDER_HPP
|
#define QUERY_ORDER_HPP
|
||||||
|
|
||||||
#include "order_details.h"
|
#include "order_details.hpp"
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef QUERY_ORDER_DETAILS_H
|
#ifndef QUERY_ORDER_DETAILS_HPP
|
||||||
#define QUERY_ORDER_DETAILS_H
|
#define QUERY_ORDER_DETAILS_HPP
|
||||||
|
|
||||||
#include "product.hpp"
|
#include "product.hpp"
|
||||||
|
|
||||||
@@ -25,4 +25,4 @@ struct order_details
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //QUERY_ORDER_DETAILS_H
|
#endif //QUERY_ORDER_DETAILS_HPP
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef QUERY_STUDENT_HPP
|
||||||
|
#define QUERY_STUDENT_HPP
|
||||||
|
|
||||||
|
#include "matador/utils/access.hpp"
|
||||||
|
#include "matador/utils/foreign_attributes.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/entity.hpp"
|
||||||
|
#include "matador/sql/has_many_to_many_relation.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::test {
|
||||||
|
|
||||||
|
class course;
|
||||||
|
|
||||||
|
struct student
|
||||||
|
{
|
||||||
|
unsigned long id{};
|
||||||
|
std::string name;
|
||||||
|
std::vector<matador::sql::entity<course>> courses;
|
||||||
|
|
||||||
|
student() = default;
|
||||||
|
explicit student(unsigned long id, std::string name)
|
||||||
|
: id(id)
|
||||||
|
, name(std::move(name)) {}
|
||||||
|
|
||||||
|
template < class Operator >
|
||||||
|
void process(Operator &op)
|
||||||
|
{
|
||||||
|
namespace field = matador::utils::access;
|
||||||
|
field::primary_key(op, "id", id);
|
||||||
|
field::attribute(op, "name", name, 255);
|
||||||
|
field::has_many_to_many(op, "student_courses", courses, "student_id", "course_id", utils::fetch_type::LAZY);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct course
|
||||||
|
{
|
||||||
|
unsigned long id{};
|
||||||
|
std::string title;
|
||||||
|
std::vector<matador::sql::entity<student>> students;
|
||||||
|
|
||||||
|
course() = default;
|
||||||
|
explicit course(unsigned long id, std::string title)
|
||||||
|
: id(id)
|
||||||
|
, title(std::move(title)) {}
|
||||||
|
|
||||||
|
template < class Operator >
|
||||||
|
void process(Operator &op)
|
||||||
|
{
|
||||||
|
namespace field = matador::utils::access;
|
||||||
|
field::primary_key(op, "id", id);
|
||||||
|
field::attribute(op, "title", title, 255);
|
||||||
|
field::has_many_to_many(op, "student_courses", students, utils::fetch_type::EAGER);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class student_course : public sql::has_many_to_many_relation<student, course>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
student_course()
|
||||||
|
: has_many_to_many_relation("student_id", "course_id") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //QUERY_STUDENT_HPP
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "auto_reset_event.hpp"
|
||||||
|
|
||||||
|
namespace matador::test::utils {
|
||||||
|
|
||||||
|
auto_reset_event::auto_reset_event() : state(false) {}
|
||||||
|
|
||||||
|
void auto_reset_event::wait_one()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
underlying.wait(lock, [this](){return state.load();});
|
||||||
|
state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void auto_reset_event::set()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
state = true;
|
||||||
|
underlying.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void auto_reset_event::reset()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
state = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef QUERY_AUTO_RESET_EVENT_HPP
|
||||||
|
#define QUERY_AUTO_RESET_EVENT_HPP
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace matador::test::utils {
|
||||||
|
|
||||||
|
class auto_reset_event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
auto_reset_event();
|
||||||
|
auto_reset_event(const auto_reset_event& other) = delete;
|
||||||
|
|
||||||
|
void wait_one();
|
||||||
|
void set();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::condition_variable underlying;
|
||||||
|
std::mutex sync;
|
||||||
|
std::atomic<bool> state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_AUTO_RESET_EVENT_HPP
|
||||||
Reference in New Issue
Block a user