Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added template API for collations #771

Merged
merged 1 commit into from
Aug 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions dev/conditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <type_traits> // std::enable_if, std::is_same
#include <vector> // std::vector
#include <tuple> // std::tuple, std::tuple_size
#include <sstream> // std::stringstream

#include "collate_argument.h"
#include "constraints.h"
Expand Down Expand Up @@ -196,6 +197,15 @@ namespace sqlite_orm {
named_collate<self> collate(std::string name) const {
return {*this, std::move(name)};
}

template<class C>
named_collate<self> collate() const {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
return {*this, std::move(name)};
}
};

struct is_not_equal_string {
Expand Down Expand Up @@ -492,6 +502,15 @@ namespace sqlite_orm {
res._collate_argument = std::move(name);
return res;
}

template<class C>
self collate() const {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
return this->collate(move(name));
}
};

/**
Expand Down
22 changes: 22 additions & 0 deletions dev/storage_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,19 @@ namespace sqlite_orm {
this->delete_function_impl(name, this->aggregateFunctions);
}

template<class C>
void create_collation() {
collating_function func = [](int leftLength, const void* lhs, int rightLength, const void* rhs) {
C collatingObject;
return collatingObject(leftLength, lhs, rightLength, rhs);
};
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
this->create_collation(name, move(func));
}

void create_collation(const std::string& name, collating_function f) {
collating_function* functionPointer = nullptr;
const auto functionExists = bool(f);
Expand All @@ -341,6 +354,15 @@ namespace sqlite_orm {
}
}

template<class C>
void delete_collation() {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
this->create_collation(name, {});
}

void begin_transaction() {
this->connection->retain();
if(1 == this->connection->retain_count()) {
Expand Down
41 changes: 41 additions & 0 deletions include/sqlite_orm/sqlite_orm.h
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,7 @@ namespace sqlite_orm {
#include <type_traits> // std::enable_if, std::is_same
#include <vector> // std::vector
#include <tuple> // std::tuple, std::tuple_size
#include <sstream> // std::stringstream

// #include "collate_argument.h"

Expand Down Expand Up @@ -2393,6 +2394,15 @@ namespace sqlite_orm {
named_collate<self> collate(std::string name) const {
return {*this, std::move(name)};
}

template<class C>
named_collate<self> collate() const {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
return {*this, std::move(name)};
}
};

struct is_not_equal_string {
Expand Down Expand Up @@ -2689,6 +2699,15 @@ namespace sqlite_orm {
res._collate_argument = std::move(name);
return res;
}

template<class C>
self collate() const {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
return this->collate(move(name));
}
};

/**
Expand Down Expand Up @@ -10482,6 +10501,19 @@ namespace sqlite_orm {
this->delete_function_impl(name, this->aggregateFunctions);
}

template<class C>
void create_collation() {
collating_function func = [](int leftLength, const void* lhs, int rightLength, const void* rhs) {
C collatingObject;
return collatingObject(leftLength, lhs, rightLength, rhs);
};
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
this->create_collation(name, move(func));
}

void create_collation(const std::string& name, collating_function f) {
collating_function* functionPointer = nullptr;
const auto functionExists = bool(f);
Expand All @@ -10506,6 +10538,15 @@ namespace sqlite_orm {
}
}

template<class C>
void delete_collation() {
std::stringstream ss;
ss << C::name();
auto name = ss.str();
ss.flush();
this->create_collation(name, {});
}

void begin_transaction() {
this->connection->retain();
if(1 == this->connection->retain_count()) {
Expand Down
37 changes: 37 additions & 0 deletions tests/select_constraints_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,40 @@ TEST_CASE("Case") {
verifyRows(rows);
}
}

TEST_CASE("Where") {
struct User {
int id = 0;
int age = 0;
std::string name;
};

auto storage = make_storage("",
make_table("users",
make_column("id", &User::id, primary_key()),
make_column("age", &User::age),
make_column("name", &User::name)));
storage.sync_schema();

storage.replace(User{1, 4, "Jeremy"});
storage.replace(User{2, 18, "Nataly"});

auto users = storage.get_all<User>();
REQUIRE(users.size() == 2);

auto users2 = storage.get_all<User>(where(true));
REQUIRE(users2.size() == 2);

auto users3 = storage.get_all<User>(where(false));
REQUIRE(users3.size() == 0);

auto users4 = storage.get_all<User>(where(true and c(&User::id) == 1));
REQUIRE(users4.size() == 1);
REQUIRE(users4.front().id == 1);

auto users5 = storage.get_all<User>(where(false and c(&User::id) == 1));
REQUIRE(users5.size() == 0);

auto users6 = storage.get_all<User>(where((false or c(&User::id) == 4) and (false or c(&User::age) == 18)));
REQUIRE(users6.empty());
}
126 changes: 78 additions & 48 deletions tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,38 @@ TEST_CASE("Custom collate") {
std::string name;
};

struct OtotoCollation {
int operator()(int leftLength, const void* lhs, int rightLength, const void* rhs) const {
if(leftLength == rightLength) {
return ::strncmp((const char*)lhs, (const char*)rhs, leftLength);
} else {
return 1;
}
}

static const char* name() {
return "ototo";
}
};

struct AlwaysEqualCollation {
int operator()(int leftLength, const void* lhs, int rightLength, const void* rhs) const {
return 0;
}

static const char* name() {
return "alwaysequal";
}
};

auto useLegacyScript = false;
SECTION("legacy API") {
useLegacyScript = true;
}
SECTION("modern API") {
useLegacyScript = false;
}

auto filename = "custom_collate.sqlite";
::remove(filename);
auto storage = make_storage(
Expand All @@ -287,45 +319,80 @@ TEST_CASE("Custom collate") {
storage.remove_all<Item>();
storage.insert(Item{0, "Mercury"});
storage.insert(Item{0, "Mars"});
storage.create_collation("ototo", [](int leftLength, const void* lhs, int rightLength, const void* rhs) {
if(leftLength == rightLength) {
return ::strncmp((const char*)lhs, (const char*)rhs, leftLength);
} else {
return 1;
}
});
storage.create_collation("alwaysequal", [](int, const void*, int, const void*) {
return 0;
});
if(useLegacyScript) {
storage.create_collation("ototo", [](int leftLength, const void* lhs, int rightLength, const void* rhs) {
if(leftLength == rightLength) {
return ::strncmp((const char*)lhs, (const char*)rhs, leftLength);
} else {
return 1;
}
});
storage.create_collation("alwaysequal", [](int, const void*, int, const void*) {
return 0;
});
} else {
storage.create_collation<OtotoCollation>();
storage.create_collation<AlwaysEqualCollation>();
}
auto rows = storage.select(&Item::name, where(is_equal(&Item::name, "Mercury").collate("ototo")));
REQUIRE(rows.size() == 1);
REQUIRE(rows.front() == "Mercury");

rows = storage.select(&Item::name, where(is_equal(&Item::name, "Mercury").collate<OtotoCollation>()));
REQUIRE(rows.size() == 1);
REQUIRE(rows.front() == "Mercury");

rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate("alwaysequal")),
order_by(&Item::name).collate("ototo"));

storage.create_collation("ototo", {});
rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate<AlwaysEqualCollation>()),
order_by(&Item::name).collate<OtotoCollation>());

if(useLegacyScript) {
storage.create_collation("ototo", {});
} else {
storage.delete_collation<OtotoCollation>();
}
try {
rows = storage.select(&Item::name, where(is_equal(&Item::name, "Mercury").collate("ototo")));
REQUIRE(false);
} catch(const std::system_error&) {
// cout << e.what() << endl;
}
try {
rows = storage.select(&Item::name, where(is_equal(&Item::name, "Mercury").collate<OtotoCollation>()));
REQUIRE(false);
} catch(const std::system_error&) {
// cout << e.what() << endl;
}
try {
rows = storage.select(&Item::name, where(is_equal(&Item::name, "Mercury").collate("ototo2")));
REQUIRE(false);
} catch(const std::system_error&) {
// cout << e.what() << endl;
}

rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate("alwaysequal")),
order_by(&Item::name).collate_rtrim());
REQUIRE(rows.size() == static_cast<size_t>(storage.count<Item>()));

rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate<AlwaysEqualCollation>()),
order_by(&Item::name).collate_rtrim());
REQUIRE(rows.size() == static_cast<size_t>(storage.count<Item>()));

rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate("alwaysequal")),
order_by(&Item::name).collate("alwaysequal"));
REQUIRE(rows.size() == static_cast<size_t>(storage.count<Item>()));

rows = storage.select(&Item::name,
where(is_equal(&Item::name, "Mercury").collate<AlwaysEqualCollation>()),
order_by(&Item::name).collate<AlwaysEqualCollation>());
REQUIRE(rows.size() == static_cast<size_t>(storage.count<Item>()));
}

TEST_CASE("collate") {
Expand Down Expand Up @@ -403,40 +470,3 @@ TEST_CASE("Escaped index name") {
make_table("users", make_column("group", &User::group)));
storage.sync_schema();
}

TEST_CASE("Where") {
struct User {
int id = 0;
int age = 0;
std::string name;
};

auto storage = make_storage("",
make_table("users",
make_column("id", &User::id, primary_key()),
make_column("age", &User::age),
make_column("name", &User::name)));
storage.sync_schema();

storage.replace(User{1, 4, "Jeremy"});
storage.replace(User{2, 18, "Nataly"});

auto users = storage.get_all<User>();
REQUIRE(users.size() == 2);

auto users2 = storage.get_all<User>(where(true));
REQUIRE(users2.size() == 2);

auto users3 = storage.get_all<User>(where(false));
REQUIRE(users3.size() == 0);

auto users4 = storage.get_all<User>(where(true and c(&User::id) == 1));
REQUIRE(users4.size() == 1);
REQUIRE(users4.front().id == 1);

auto users5 = storage.get_all<User>(where(false and c(&User::id) == 1));
REQUIRE(users5.size() == 0);

auto users6 = storage.get_all<User>(where((false or c(&User::id) == 4) and (false or c(&User::age) == 18)));
REQUIRE(users6.empty());
}