Skip to content
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
14 changes: 13 additions & 1 deletion .clang-format
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
BasedOnStyle: google
BasedOnStyle: Google
DerivePointerAlignment: false
IncludeBlocks: Preserve
AttributeMacros: ["noexcept"]
IndentRequires: false
ColumnLimit: 120
IndentWidth: 4
TabWidth: 4
AccessModifierOffset: -4
BinPackParameters: false
BinPackArguments: false
AllowAllParametersOfDeclarationOnNextLine: false
AlignAfterOpenBracket: BlockIndent
AlwaysBreakAfterDefinitionReturnType: None
PenaltyReturnTypeOnItsOwnLine: 200
124 changes: 54 additions & 70 deletions src/cache/articles_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,78 @@
namespace real_medium::cache::articles_cache {

userver::storages::postgres::Query ArticlesCachePolicy::kQuery =
userver::storages::postgres::Query(
real_medium::sql::kSelectFullArticleInfo.data());
userver::storages::postgres::Query(real_medium::sql::kSelectFullArticleInfo.data());

void ArticlesCacheContainer::insert_or_assign(Key&& key, Article&& article) {
auto articlePtr = std::make_shared<const Article>(std::move(article));
auto oldValue = articleByKey_.find(key);
if (oldValue != articleByKey_.end()) {
articleBySlug_.erase(oldValue->second->slug);
for (const auto& oldFollower : oldValue->second->authorFollowedByUsersIds)
if (articlePtr->authorFollowedByUsersIds.find(oldFollower) ==
articlePtr->authorFollowedByUsersIds.end())
articlesByFollower_[oldFollower].erase(articlePtr->articleId);
}
auto articlePtr = std::make_shared<const Article>(std::move(article));
auto oldValue = articleByKey_.find(key);
if (oldValue != articleByKey_.end()) {
articleBySlug_.erase(oldValue->second->slug);
for (const auto& oldFollower : oldValue->second->authorFollowedByUsersIds)
if (articlePtr->authorFollowedByUsersIds.find(oldFollower) == articlePtr->authorFollowedByUsersIds.end())
articlesByFollower_[oldFollower].erase(articlePtr->articleId);
}

articleByKey_.insert_or_assign(key, articlePtr);
articleBySlug_.insert_or_assign(articlePtr->slug, articlePtr);
for (const auto& follower : articlePtr->authorFollowedByUsersIds)
articlesByFollower_[follower].insert_or_assign(articlePtr->articleId,
articlePtr);
recentArticles_.insert_or_assign(
{articlePtr->createdAt, articlePtr->articleId}, articlePtr);
articleByKey_.insert_or_assign(key, articlePtr);
articleBySlug_.insert_or_assign(articlePtr->slug, articlePtr);
for (const auto& follower : articlePtr->authorFollowedByUsersIds)
articlesByFollower_[follower].insert_or_assign(articlePtr->articleId, articlePtr);
recentArticles_.insert_or_assign({articlePtr->createdAt, articlePtr->articleId}, articlePtr);
}

size_t ArticlesCacheContainer::size() const { return articleByKey_.size(); }

ArticlesCacheContainer::ArticlePtr ArticlesCacheContainer::findArticleBySlug(
const Slug& slug) const {
auto it = articleBySlug_.find(slug);
if (it == articleBySlug_.end()) return nullptr;
return it->second;
ArticlesCacheContainer::ArticlePtr ArticlesCacheContainer::findArticleBySlug(const Slug& slug) const {
auto it = articleBySlug_.find(slug);
if (it == articleBySlug_.end()) return nullptr;
return it->second;
}

std::vector<ArticlesCacheContainer::ArticlePtr>
ArticlesCacheContainer::getRecent(
real_medium::handlers::ArticleFilterDTO& filter) const {
std::vector<ArticlePtr> articles;
int offset = 0;
for (const auto& it : recentArticles_) {
if (filter.limit &&
articles.size() >=
userver::utils::numeric_cast<std::size_t>(filter.limit))
break;
std::vector<ArticlesCacheContainer::ArticlePtr> ArticlesCacheContainer::getRecent(
real_medium::handlers::ArticleFilterDTO& filter
) const {
std::vector<ArticlePtr> articles;
int offset = 0;
for (const auto& it : recentArticles_) {
if (filter.limit && articles.size() >= userver::utils::numeric_cast<std::size_t>(filter.limit)) break;

const auto& tags = it.second->tags;
if (filter.tag && it.second->tags.find(filter.tag.value()) == tags.end())
continue;
const auto& tags = it.second->tags;
if (filter.tag && it.second->tags.find(filter.tag.value()) == tags.end()) continue;

if (filter.author && it.second->authorInfo.username != filter.author)
continue;
if (filter.author && it.second->authorInfo.username != filter.author) continue;

const auto& favorited = it.second->articleFavoritedByUsernames;
if (filter.favorited &&
favorited.find(filter.favorited.value()) == favorited.end())
continue;
const auto& favorited = it.second->articleFavoritedByUsernames;
if (filter.favorited && favorited.find(filter.favorited.value()) == favorited.end()) continue;

if (filter.offset && offset < filter.offset) {
++offset;
continue;
if (filter.offset && offset < filter.offset) {
++offset;
continue;
}
articles.push_back(it.second);
}
articles.push_back(it.second);
}
return articles;
return articles;
}
std::vector<ArticlesCacheContainer::ArticlePtr> ArticlesCacheContainer::getFeed(
real_medium::handlers::FeedArticleFilterDTO& filter, UserId authId) const {
auto followedArticlesUMap = articlesByFollower_.find(authId);
if (followedArticlesUMap == articlesByFollower_.end()) return {};
std::vector<ArticlesCacheContainer::ArticlePtr>
ArticlesCacheContainer::getFeed(real_medium::handlers::FeedArticleFilterDTO& filter, UserId authId) const {
auto followedArticlesUMap = articlesByFollower_.find(authId);
if (followedArticlesUMap == articlesByFollower_.end()) return {};

RecentArticlesMap followedArticlesOrdered;
for (const auto& it : followedArticlesUMap->second)
followedArticlesOrdered.insert_or_assign(
{it.second->createdAt, it.second->articleId}, it.second);
RecentArticlesMap followedArticlesOrdered;
for (const auto& it : followedArticlesUMap->second)
followedArticlesOrdered.insert_or_assign({it.second->createdAt, it.second->articleId}, it.second);

std::vector<ArticlePtr> articles;
;
int offset = 0;
for (const auto& it : followedArticlesOrdered) {
if (filter.limit &&
articles.size() >=
userver::utils::numeric_cast<std::size_t>(filter.limit))
break;
if (filter.offset && offset < filter.offset) {
++offset;
continue;
std::vector<ArticlePtr> articles;
;
int offset = 0;
for (const auto& it : followedArticlesOrdered) {
if (filter.limit && articles.size() >= userver::utils::numeric_cast<std::size_t>(filter.limit)) break;
if (filter.offset && offset < filter.offset) {
++offset;
continue;
}
articles.push_back(it.second);
}
articles.push_back(it.second);
}
return articles;
return articles;
}

} // namespace real_medium::cache::articles_cache
89 changes: 40 additions & 49 deletions src/cache/articles_cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,65 +4,56 @@
#include <unordered_map>
#include <userver/cache/base_postgres_cache.hpp>
#include <userver/storages/postgres/io/chrono.hpp>
#include "../db/sql.hpp"
#include "../dto/filter.hpp"
#include "../models/article.hpp"
#include "db/sql.hpp"
#include "dto/filter.hpp"
#include "models/article.hpp"

namespace real_medium::cache::articles_cache {
class ArticlesCacheContainer {
using Timepoint = userver::storages::postgres::TimePointTz;
using Slug = std::string;
using UserId = std::string;
using Timepoint = userver::storages::postgres::TimePointTz;
using Slug = std::string;
using UserId = std::string;

public:
using Key = real_medium::models::ArticleId;
using Article = real_medium::models::FullArticleInfo;
using ArticlePtr = std::shared_ptr<const Article>;
using AuthorName = std::string;
void insert_or_assign(Key&& key, Article&& config);
size_t size() const;
public:
using Key = real_medium::models::ArticleId;
using Article = real_medium::models::FullArticleInfo;
using ArticlePtr = std::shared_ptr<const Article>;
using AuthorName = std::string;
void insert_or_assign(Key&& key, Article&& config);
size_t size() const;

ArticlePtr findArticleBySlug(const Slug& slug) const;
std::vector<ArticlePtr> getRecent(
real_medium::handlers::ArticleFilterDTO& filter_) const;
std::vector<ArticlePtr> getFeed(
real_medium::handlers::FeedArticleFilterDTO& filter_,
UserId authId_) const;
ArticlePtr findArticleBySlug(const Slug& slug) const;
std::vector<ArticlePtr> getRecent(real_medium::handlers::ArticleFilterDTO& filter_) const;
std::vector<ArticlePtr> getFeed(real_medium::handlers::FeedArticleFilterDTO& filter_, UserId authId_) const;

private:
struct TimepointedArticle {
Timepoint created;
Key articleId;
bool operator<(const TimepointedArticle& other) const {
return created != other.created ? created < other.created
: articleId < other.articleId;
}
bool operator==(const TimepointedArticle& other) const {
return created == other.created && articleId == other.articleId;
}
bool operator>(const TimepointedArticle& other) const {
return !(*this == other) && !(*this < other);
}
};
private:
struct TimepointedArticle {
Timepoint created;
Key articleId;
bool operator<(const TimepointedArticle& other) const {
return created != other.created ? created < other.created : articleId < other.articleId;
}
bool operator==(const TimepointedArticle& other) const {
return created == other.created && articleId == other.articleId;
}
bool operator>(const TimepointedArticle& other) const { return !(*this == other) && !(*this < other); }
};

using RecentArticlesMap =
std::map<TimepointedArticle /*created_at*/, ArticlePtr,
std::greater<TimepointedArticle>>;
std::unordered_map<Key, ArticlePtr> articleByKey_;
std::unordered_map<Slug, ArticlePtr> articleBySlug_;
std::unordered_map<UserId /*follower*/, std::unordered_map<Key, ArticlePtr>>
articlesByFollower_;
RecentArticlesMap recentArticles_;
using RecentArticlesMap = std::map<TimepointedArticle /*created_at*/, ArticlePtr, std::greater<TimepointedArticle>>;
std::unordered_map<Key, ArticlePtr> articleByKey_;
std::unordered_map<Slug, ArticlePtr> articleBySlug_;
std::unordered_map<UserId /*follower*/, std::unordered_map<Key, ArticlePtr>> articlesByFollower_;
RecentArticlesMap recentArticles_;
};

struct ArticlesCachePolicy {
static constexpr auto kName = "articles-cache";
using ValueType = ArticlesCacheContainer::Article;
using CacheContainer = ArticlesCacheContainer;
static constexpr auto kKeyMember = &ValueType::articleId;
static userver::storages::postgres::Query kQuery;
static constexpr auto kUpdatedField = "updated_at";
using UpdatedFieldType = userver::storages::postgres::TimePointTz;
static constexpr auto kName = "articles-cache";
using ValueType = ArticlesCacheContainer::Article;
using CacheContainer = ArticlesCacheContainer;
static constexpr auto kKeyMember = &ValueType::articleId;
static userver::storages::postgres::Query kQuery;
static constexpr auto kUpdatedField = "updated_at";
using UpdatedFieldType = userver::storages::postgres::TimePointTz;
};
using ArticlesCache = ::userver::components::PostgreCache<ArticlesCachePolicy>;
} // namespace real_medium::cache::articles_cache
40 changes: 20 additions & 20 deletions src/cache/comments_cache.cpp
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
#include <userver/cache/base_postgres_cache.hpp>
#include <userver/storages/postgres/io/chrono.hpp>
#include "userver/storages/postgres/query.hpp"
#include "userver/utils/algo.hpp"
#include <userver/storages/postgres/query.hpp>
#include <userver/utils/algo.hpp>

#include "comments_cache.hpp"
#include "db/sql.hpp"

namespace real_medium::cache::comments_cache {

userver::storages::postgres::Query CommentCachePolicy::kQuery =
userver::storages::postgres::Query(
real_medium::sql::kSelectCachedComments.data());
userver::storages::postgres::Query(real_medium::sql::kSelectCachedComments.data());

void CommentsCacheContainer::insert_or_assign(
real_medium::cache::comments_cache::CommentsCacheContainer::Key&& commentId,
real_medium::cache::comments_cache::CommentsCacheContainer::Comment&&
comment) {
auto commentPtr = std::make_shared<const Comment>(std::move(comment));
if (comment_to_key_.count(commentId)) {
auto& oldSlug = comment_to_key_[commentId]->slug;
if (oldSlug != commentPtr->slug) {
auto& comments = comments_to_slug_[oldSlug];
comments_to_slug_[commentPtr->slug] = comments;
comments_to_slug_.erase(oldSlug);
real_medium::cache::comments_cache::CommentsCacheContainer::Comment&& comment
) {
auto commentPtr = std::make_shared<const Comment>(std::move(comment));
if (comment_to_key_.count(commentId)) {
auto& oldSlug = comment_to_key_[commentId]->slug;
if (oldSlug != commentPtr->slug) {
auto& comments = comments_to_slug_[oldSlug];
comments_to_slug_[commentPtr->slug] = comments;
comments_to_slug_.erase(oldSlug);
}
}
}
comment_to_key_.insert_or_assign(commentId, commentPtr);
comments_to_slug_[commentPtr->slug].insert_or_assign(commentId, commentPtr);
comment_to_key_.insert_or_assign(commentId, commentPtr);
comments_to_slug_[commentPtr->slug].insert_or_assign(commentId, commentPtr);
};

size_t CommentsCacheContainer::size() const { return comment_to_key_.size(); }

std::map<CommentsCacheContainer::Key, CommentsCacheContainer::CommentPtr>
CommentsCacheContainer::findComments(const Slug& slug) const {
if (!comments_to_slug_.count(slug)) return {};
return comments_to_slug_.at(slug);
std::map<CommentsCacheContainer::Key, CommentsCacheContainer::CommentPtr> CommentsCacheContainer::findComments(
const Slug& slug
) const {
if (!comments_to_slug_.count(slug)) return {};
return comments_to_slug_.at(slug);
}

} // namespace real_medium::cache::comments_cache
36 changes: 18 additions & 18 deletions src/cache/comments_cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@
namespace real_medium::cache::comments_cache {

class CommentsCacheContainer {
public:
using Key = real_medium::models::CommentId;
using Comment = real_medium::models::CachedComment;
using CommentPtr = std::shared_ptr<const Comment>;
using Slug = std::string;
void insert_or_assign(Key&& key, Comment&& config);
size_t size() const;
public:
using Key = real_medium::models::CommentId;
using Comment = real_medium::models::CachedComment;
using CommentPtr = std::shared_ptr<const Comment>;
using Slug = std::string;
void insert_or_assign(Key&& key, Comment&& config);
size_t size() const;

std::map<Key, CommentPtr> findComments(const Slug& key) const;
std::map<Key, CommentPtr> findComments(const Slug& key) const;

private:
std::unordered_map<Slug, std::map<Key, CommentPtr>> comments_to_slug_;
std::unordered_map<Key, CommentPtr> comment_to_key_;
private:
std::unordered_map<Slug, std::map<Key, CommentPtr>> comments_to_slug_;
std::unordered_map<Key, CommentPtr> comment_to_key_;
};

struct CommentCachePolicy {
static constexpr auto kName = "comments-cache";
using ValueType = real_medium::models::CachedComment;
using CacheContainer = CommentsCacheContainer;
static constexpr auto kKeyMember = &real_medium::models::CachedComment::id;
static userver::storages::postgres::Query kQuery;
static constexpr auto kUpdatedField = "c.updated_at";
using UpdatedFieldType = userver::storages::postgres::TimePointTz;
static constexpr auto kName = "comments-cache";
using ValueType = real_medium::models::CachedComment;
using CacheContainer = CommentsCacheContainer;
static constexpr auto kKeyMember = &real_medium::models::CachedComment::id;
static userver::storages::postgres::Query kQuery;
static constexpr auto kUpdatedField = "c.updated_at";
using UpdatedFieldType = userver::storages::postgres::TimePointTz;
};

using CommentsCache = ::userver::components::PostgreCache<CommentCachePolicy>;
Expand Down
Loading