mirror of
https://github.com/getml/sqlgen.git
synced 2026-05-06 07:02:46 -05:00
Co-authored-by: Scott Fries <Scott@ScottFries.com>
This commit is contained in:
@@ -50,6 +50,44 @@ To create a cache with a virtually unlimited size, you can specify a `max_size`
|
||||
const auto cached_query = sqlgen::cache<0>(query);
|
||||
```
|
||||
|
||||
### Cache Invalidation
|
||||
|
||||
The cache has no mechanism for determining if a cached result is still valid/up-to-date. Because of this, the cache should be explicitly `clear`ed before use any time another query is made that invalidates the cache.
|
||||
|
||||
```cpp
|
||||
#include <sqlgen.hpp>
|
||||
|
||||
struct User {
|
||||
std::string name;
|
||||
int age;
|
||||
};
|
||||
|
||||
const auto conn = sqlgen::sqlite::connect();
|
||||
|
||||
const auto user = User{.name = "John", .age = 30};
|
||||
sqlgen::write(conn, user);
|
||||
|
||||
const auto user_b = User{.name = "Mary", .age = 25};
|
||||
sqlgen::write(conn, user_b);
|
||||
|
||||
const auto query = sqlgen::read<std::vector<User>>;
|
||||
const auto cached_query = sqlgen::cache<100>(query);
|
||||
|
||||
const auto users1 = cached_query(conn).value();
|
||||
// The cache size will now contain a result consisting of John & Mary
|
||||
|
||||
const auto user_c = User{.name = "Bill", .age = 50};
|
||||
sqlgen::write(conn, user_c);
|
||||
|
||||
// Because the query was previously cached, user2 will still only contain John & Mary while Bill will be absent.
|
||||
const auto users2 = cached_query(conn).value();
|
||||
|
||||
cached_query.clear(conn);
|
||||
|
||||
// Now, the query will be executed again since it's no longer cached. Afterwards, the cache will again store an up-to-date result and users3 will contain John, Mary, & Bill.
|
||||
const auto users3 = cached_query(conn).value();
|
||||
```
|
||||
|
||||
### Thread Safety and Concurrency
|
||||
|
||||
The cache is thread-safe and can be accessed from multiple threads concurrently. A `std::shared_mutex` is used to protect the cache from data races.
|
||||
|
||||
@@ -65,6 +65,11 @@ class CacheImpl {
|
||||
});
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
std::unique_lock write_lock(mtx_);
|
||||
cache_.clear();
|
||||
}
|
||||
|
||||
static const auto& cache() { return cache_; }
|
||||
|
||||
private:
|
||||
@@ -107,6 +112,12 @@ struct Cache {
|
||||
_max_size>::cache();
|
||||
}
|
||||
|
||||
template <class Connection>
|
||||
requires is_connection<Connection>
|
||||
static void clear(const Result<Ref<Connection>>&) {
|
||||
CacheImpl<QueryT, std::remove_cvref_t<Connection>, _max_size>::clear();
|
||||
}
|
||||
|
||||
QueryT query_;
|
||||
};
|
||||
|
||||
|
||||
+19
-11
@@ -26,20 +26,28 @@ TEST(duckdb, test_cache) {
|
||||
|
||||
const auto cached_query = sqlgen::cache<100>(query);
|
||||
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
auto test_cache_population = [&]() {
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
};
|
||||
test_cache_population();
|
||||
|
||||
// Test cache invalidation
|
||||
cached_query.clear(conn);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 0);
|
||||
test_cache_population();
|
||||
}
|
||||
|
||||
} // namespace test_cache
|
||||
|
||||
+19
-11
@@ -33,20 +33,28 @@ TEST(mysql, test_cache) {
|
||||
|
||||
const auto cached_query = sqlgen::cache<100>(query);
|
||||
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
auto test_cache_population = [&]() {
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
};
|
||||
test_cache_population();
|
||||
|
||||
// Test cache invalidation
|
||||
cached_query.clear(conn);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 0);
|
||||
test_cache_population();
|
||||
}
|
||||
|
||||
} // namespace test_cache
|
||||
|
||||
@@ -33,20 +33,28 @@ TEST(postgres, test_cache) {
|
||||
|
||||
const auto cached_query = sqlgen::cache<100>(query);
|
||||
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
auto test_cache_population = [&]() {
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
};
|
||||
test_cache_population();
|
||||
|
||||
// Test cache invalidation
|
||||
cached_query.clear(conn);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 0);
|
||||
test_cache_population();
|
||||
}
|
||||
|
||||
} // namespace test_cache
|
||||
|
||||
+19
-11
@@ -26,20 +26,28 @@ TEST(sqlite, test_cache) {
|
||||
|
||||
const auto cached_query = sqlgen::cache<100>(query);
|
||||
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
auto test_cache_population = [&]() {
|
||||
const auto user1 = conn.and_then(cache<100>(query)).value();
|
||||
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
const auto user2 = cached_query(conn).value();
|
||||
const auto user3 = cached_query(conn).value();
|
||||
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
EXPECT_EQ(user1.name, "John");
|
||||
EXPECT_EQ(user1.age, 30);
|
||||
EXPECT_EQ(user2.name, "John");
|
||||
EXPECT_EQ(user2.age, 30);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 1);
|
||||
EXPECT_EQ(user3.name, "John");
|
||||
EXPECT_EQ(user3.age, 30);
|
||||
};
|
||||
test_cache_population();
|
||||
|
||||
// Test cache invalidation
|
||||
cached_query.clear(conn);
|
||||
EXPECT_EQ(cached_query.cache(conn).size(), 0);
|
||||
test_cache_population();
|
||||
}
|
||||
|
||||
} // namespace test_cache
|
||||
|
||||
Reference in New Issue
Block a user