implemented prepared statement for postgres and sqlite

This commit is contained in:
2023-12-09 11:08:03 +01:00
parent 8ba70cc79e
commit da423ea8bb
59 changed files with 1769 additions and 314 deletions
+3 -1
View File
@@ -25,7 +25,9 @@ add_executable(tests QueryBuilderTest.cpp
models/person.hpp
AnyTypeToVisitorTest.cpp
ColumnTest.cpp
SessionRecordTest.cpp)
SessionRecordTest.cpp
StatementCacheTest.cpp
StatementTest.cpp)
target_link_libraries(tests PRIVATE
Catch2::Catch2WithMain
matador
+23 -11
View File
@@ -2,13 +2,13 @@
#include <matador/sql/column.hpp>
#include <matador/sql/condition.hpp>
#include <matador/sql/dialect.hpp>
#include <matador/sql/dialect_builder.hpp>
#include <matador/sql/query_builder.hpp>
using namespace matador::sql;
TEST_CASE("Create table sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
auto q = query.create().table("person", {
make_pk_column<unsigned long>("id"),
@@ -31,7 +31,7 @@ TEST_CASE("Create table sql statement string", "[query]") {
}
TEST_CASE("Drop table sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.drop().table("person").compile();
@@ -40,7 +40,7 @@ TEST_CASE("Drop table sql statement string", "[query]") {
}
TEST_CASE("Select sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.select({"id", "name", "age"}).from("person").compile();
@@ -49,7 +49,7 @@ TEST_CASE("Select sql statement string", "[query]") {
}
TEST_CASE("Insert sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.insert().into("person", {
"id", "name", "age"
@@ -60,7 +60,7 @@ TEST_CASE("Insert sql statement string", "[query]") {
}
TEST_CASE("Update sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.update("person").set({
{"id", 7UL},
@@ -73,7 +73,7 @@ TEST_CASE("Update sql statement string", "[query]") {
}
TEST_CASE("Delete sql statement string", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.remove().from("person").compile();
@@ -82,7 +82,7 @@ TEST_CASE("Delete sql statement string", "[query]") {
}
TEST_CASE("Select sql statement string with where clause", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
auto q = query.select({"id", "name", "age"})
.from("person")
@@ -101,8 +101,20 @@ TEST_CASE("Select sql statement string with where clause", "[query]") {
REQUIRE(q.table_name == "person");
}
TEST_CASE("Insert sql statement with placeholder", "[query]") {
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.insert().into("person", {
"id", "name", "age"
}).values({_, _, _}).compile();
REQUIRE(q.sql == R"(INSERT INTO "person" ("id", "name", "age") VALUES (?, ?, ?))");
REQUIRE(q.table_name == "person");
REQUIRE(q.bind_vars.size() == 3);
}
TEST_CASE("Select sql statement string with order by", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.select({"id", "name", "age"})
.from("person")
@@ -114,7 +126,7 @@ TEST_CASE("Select sql statement string with order by", "[query]") {
}
TEST_CASE("Select sql statement string with group by", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.select({"id", "name", "age"})
.from("person")
@@ -126,7 +138,7 @@ TEST_CASE("Select sql statement string with group by", "[query]") {
}
TEST_CASE("Select sql statement string with offset and limit", "[query]") {
dialect d;
dialect d = dialect_builder::builder().create().build();
query_builder query(d);
const auto q = query.select({"id", "name", "age"})
.from("person")
+1 -1
View File
@@ -365,7 +365,7 @@ TEST_CASE("Execute delete statement", "[session record]") {
.where("id"_col == 1)
.execute();
REQUIRE(res.second == R"(DELETE FROM "person" WHERE "id" = 1)");
REQUIRE(res.second == R"(DELETE FROM "main"."person" WHERE "id" = 1)");
REQUIRE(res.first == 1);
count = s.select({count_all()}).from("person").fetch_value<int>();
+31
View File
@@ -0,0 +1,31 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/sql/connection_info.hpp"
#include "matador/sql/connection_pool.hpp"
#include "matador/sql/session.hpp"
#include "matador/sql/statement_cache.hpp"
using namespace matador;
class TestConnection
{
public:
explicit TestConnection(sql::connection_info info)
: info_(std::move(info)) {}
void open() {}
private:
sql::connection_info info_;
};
TEST_CASE("Acquire prepared statement", "[statement cache]") {
sql::statement_cache cache;
sql::connection_pool<TestConnection> pool("sqlite://sqlite.db", 4);
// sql::session s(pool);
// auto conn = pool.acquire();
std::string sql = R"(SELECT * FROM person WHERE name = 'george')";
// auto stmt = cache.acquire(sql, conn);
}
+119
View File
@@ -0,0 +1,119 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/catch_template_test_macros.hpp>
#include "matador/sql/column.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/connection_info.hpp"
#include "matador/sql/connection_pool.hpp"
#include "matador/sql/session.hpp"
#include "models/airplane.hpp"
using namespace matador::sql;
using namespace matador::test;
struct Postgres
{
// constexpr static const char *dns{"postgres://test:test123@127.0.0.1:15432/test"};
constexpr static const char *dns{"postgres://test:test123@127.0.0.1:5432/matador_test"};
};
struct Sqlite
{
constexpr static const char *dns{"sqlite://sqlite.db"};
};
template<class Type>
class StatementTestFixture
{
public:
StatementTestFixture()
: pool_(Type::dns, 4), session_(pool_)
{
auto res = session_.create()
.table<airplane>("airplane")
.execute();
REQUIRE(res.first == 0);
REQUIRE(res.second == R"(CREATE TABLE "airplane" ("id" BIGINT, "brand" VARCHAR(255), "model" VARCHAR(255), CONSTRAINT PK_airplane PRIMARY KEY (id)))");
}
~StatementTestFixture()
{
session_.drop().table("airplane").execute();
}
matador::sql::session &session()
{ return session_; }
std::vector<entity<airplane>> &planes()
{ return planes_; }
private:
matador::sql::connection_pool<matador::sql::connection> pool_;
matador::sql::session session_;
std::vector<entity<airplane>> planes_{
make_entity<airplane>(1, "Airbus", "A380"),
make_entity<airplane>(2, "Boeing", "707"),
make_entity<airplane>(3, "Boeing", "747")
};
};
TEMPLATE_TEST_CASE_METHOD(StatementTestFixture, "Create prepared statement", "[statement]", Sqlite, Postgres)
{
auto &s = StatementTestFixture<TestType>::session();
auto &planes = StatementTestFixture<TestType>::planes();
SECTION("Insert with prepared statement and placeholder") {
auto stmt = s.insert()
.template into<airplane>("airplane")
.template values<airplane>().prepare();
for (const auto &plane: planes) {
auto res = stmt.bind(*plane).execute();
REQUIRE(res == 1);
stmt.reset();
}
auto result = s.template select<airplane>().from("airplane").template fetch_all<airplane>();
size_t index{0};
for (const auto &i: result) {
REQUIRE(i.id == planes[index]->id);
REQUIRE(i.brand == planes[index]->brand);
REQUIRE(i.model == planes[index++]->model);
}
}
SECTION("Select with prepared statement") {
for (const auto &plane: planes) {
auto res = s.insert().template into<airplane>("airplane").values(*plane).execute();
REQUIRE(res.first == 1);
}
auto stmt = s.template select<airplane>().from("airplane").where("brand"_col == _).prepare();
stmt.bind(0, "Airbus");
auto result = stmt.template fetch<airplane>();
for (const auto &i: result) {
REQUIRE(i.id == planes[0]->id);
REQUIRE(i.brand == planes[0]->brand);
REQUIRE(i.model == planes[0]->model);
}
stmt.reset();
stmt.bind(0, "Boeing");
result = stmt.template fetch<airplane>();
size_t index{1};
for (const auto &i: result) {
REQUIRE(i.id == planes[index]->id);
REQUIRE(i.brand == planes[index]->brand);
REQUIRE(i.model == planes[index++]->model);
}
}
}