def update(self, comments: ["Comment"]): """ Update sorted comments in cache This should be called on votes (maybe not all of them) and on new comments :param link_id: link id :param comment: comment """ for comment in comments: cache_key = self._cache_key(comment.parent_id) lock_key = self._lock_key(comment.parent_id) # update comment under read - write - modify lock with Lock(cache.conn, lock_key): # maybe check against the comment tree to see if it is missing or it just is not initialized yet comments = ( cache.get(cache_key) or [] ) # so maybe load comments instead of [] # update comment for i in range(len(comments)): if comments[i][0] == comment.id: comments[i] = [ comment.id, confidence(comment.ups, comment.downs), ] break else: # add comment comments.append( [comment.id, confidence(comment.ups, comment.downs)] ) # sort and save comments = sorted(comments, key=lambda x: x[1:], reverse=True) cache.set(cache_key, comments)
def by_slug(cls, slug: str) -> Optional["Feed"]: """ Get feed by slug :param username: slug :return: """ cache_key = "fslug:{}".format(slug) # check feed slug cache in_cache = cache.get(cache_key, raw=True) uid = int(in_cache) if in_cache else None # return user on success if uid is not None: return Feed.by_id(uid) # try to load user from DB on failure feed = Feed.where("slug", slug).first() # cache the result if feed is not None: cache.set(cache_key, feed.id, raw=True) feed.write_to_cache() return feed
def by_username(cls, username: str) -> Optional["User"]: """ Get user by username :param username: username :return: """ cache_key = "uname:{}".format(username) # check username cache in_cache = cache.get(cache_key, raw=True) uid = int(in_cache) if in_cache else None # return user on success if uid is not None: return User.by_id(uid) # try to load user from DB on failure u = User.where("username", username).first() # cache the result if u is not None: cache.set(cache_key, u.id, raw=True) u.write_to_cache() return u
def subscribe(self, feed: "Feed"): """ Subscribe user to given feed :param feed: feed to subscribe :return: """ if self.feed_subs >= MAX_SUBSCRIPTIONS_FREE: return False # if user is banned from feed he can't subscribe if Ban.by_user_and_feed(self, feed) is not None: return False # save subscription db.table("feeds_users").insert(user_id=self.id, feed_id=feed.id) key = "subs:{}".format(self.id) ids = cache.get(key) or [] ids.append(feed.id) cache.set(key, ids) self.incr("feed_subs", 1) self.update_with_cache() # TODO DO IN QUEUE feed.incr("subscribers_count", 1) return True
def update_from_cache(self): """ Update model from redis This is usually performed before updates or when updating for data consistency """ data = cache.get(self._cache_key) if data is not None: self.set_raw_attributes(data)
def by_user_and_feed_id(cls, user_id, feed_id) -> "Ban": """ Get ban by user id and feed id :param user_id: user id :param feed_id: feed id :return: ban """ return cache.get(cls.cache_key(user_id, feed_id))
def subscribed_feed_ids(self) -> List[str]: """ Get users subscribed feed ids :return: list of ids """ key = "subs:{}".format(self.id) ids = cache.get(key) if ids is None: ids = [feed.id for feed in self.feeds] cache.set(key, ids) return ids
def load_from_cache(cls, id: str) -> object: """ Load model from cache :param id: id :return: model if found else None """ data = cache.get(cls._cache_key_from_id(id)) if data is None: return None obj = cls() obj.set_raw_attributes(data) obj.set_exists(True) return obj
def delete(self, links): """ Delete given links from query :param links: links """ with Lock(cache.conn, self._lock_key): # fetch fresh data from cache data = cache.get(self._cache_key) or [] lids = set(x.id for x in links) data = [x for x in data if x[0] not in lids] self._data = data self._fetched = True self._save()
def unsubscribe(self, feed: "Feed"): db.table("feeds_users").where("user_id", "=", self.id).where("feed_id", "=", feed.id).delete() self.decr("feed_subs", 1) # TODO DO IN QUEUE feed.decr("subscribers_count", 1) key = "subs:{}".format(self.id) ids = cache.get(key) if ids is not None: ids = [id for id in ids if id != feed.id] cache.set(key, ids) return True
def by_slug(cls, slug) -> Optional["Link"]: """ Get link by slug :param slug: slug :return: maybe link """ cache_key = "lslug:{}".format(slug) id = cache.get(cache_key) if id is None: link = Link.where("slug", slug).first() if link is not None: id = link.id cache.set(cache_key, id) return Link.by_id(id) if id else None
def load_tree(self) -> dict: """ Load the tree :return: tree """ tree = cache.get(self._cache_key) if not tree: comments = ( Comment.where("link_id", self.link_id).select("parent_id", "id").get() or [] ) tree = {} for comment in comments: tree.setdefault(comment.parent_id, []).append(comment.id) cache.set(self._cache_key, tree) self._tree = tree return tree
def fetch(self): """ Fetch data from cache and return them Data are tuples in from [id, [sort value 1, [sort value 2, ...]]] :return: sorted and filtered list of [id, sort values...] tuples """ self._data = cache.get(self._cache_key) if self._data is None: CACHE_MISSES.inc(1) self._rebuild() else: CACHE_HITS.inc(1) self._fetched = True for fnc in self._filters: self._data = filter(fnc, self._data) return self._data
def get_by_feed_id(cls, feed_id: int, sort: str) -> ["Link"]: """ Get links by feed id and sort :param feed_id: :param sort: :return: """ cache_key = "fs:{}.{}".format(feed_id, sort) r = cache.get(cache_key) if r is not None: return r q = Link.where("feed_id", feed_id).order_by_raw(sorts[sort]) # cache needs array of objects, not a orator collection res = [f for f in q.limit(1000).get()] # TODO this is stupid, cache only ids? cache.set(cache_key, res) return res
def load_user(session_id: str) -> Optional["User"]: """ Load user by session id Loads the user by session id from cache :param session_id: session id :return: maybe user """ user_id = cache.get("us:{}".format(session_id), raw=True) if not user_id: return None uid = int(user_id) u = User.by_id(uid) if u is not None: u._accessor_cache["session_token"] = session_id return u
def rules_html(self): rules = cache.get(self.rules_cache_key) if rules is None: rules = markdown(self.rules) if self.rules else "" cache.set(self.rules_cache_key, rules) return rules
def user_id(self): """ Returns ID of user for whom this verification applies :return: user ID """ return int(cache.get(self._cache_key, raw=True))
def verify(self): """ Checks if given verification exists :return: """ return cache.get(self._cache_key, raw=True) is not None