class ScheduleConsFollowers(Followers, metaclass=delegation_metaclass("_followers")): def __init__( self, user: User, followers: Followers, follow_schedule: FollowSchedule, unfollow_schedule: UnfollowSchedule, pgsql: PgsqlBase, ): self._followers = followers self._follow_schedule = follow_schedule self._unfollow_schedule = unfollow_schedule self._pgsql = pgsql self._user = user def users(self): return map( lambda u: ScheduleConsistentUser(u, self._follow_schedule, self. _unfollow_schedule, self._pgsql), self._followers.users(), ) def update_followers(self, users): users = list(users) self._followers.update_followers(users) for u in users: self._follow_schedule.mark_fulfilled(u, self._user)
class ScheduleConsistentUser(User, metaclass=delegation_metaclass("_user")): # TODO: write tests ScheduleConsistentUser def __init__( self, user: User, follow_schedule: FollowSchedule, unfollow_schedule: UnfollowSchedule, pgsql: PgsqlBase, ): self._user = user self._pgsql = pgsql self._follow_schedule = follow_schedule self._unfollow_schedule = unfollow_schedule def following(self) -> "Following": return ScheduleConsFollowing( self, self._user.following(), self._follow_schedule, self._unfollow_schedule, self._pgsql, ) def followers(self) -> "Followers": return ScheduleConsFollowers( self, self._user.followers(), self._follow_schedule, self._unfollow_schedule, self._pgsql, )
class CachedLazyUser(InstaUser, metaclass=delegation_metaclass("_lazy_user")): def __init__(self, insta_user: InstaUser, actions: Actions, db_user: User, make_insta_user: Callable[[User], InstaUser]): self._lazy_user = LazyInstaUser(insta_user=insta_user, actions=actions, db_user=db_user) self._make_user = make_insta_user self._db_user = db_user def retrieve_followers(self): print("cached user retreiving followers") self.save_followers() return [self._make_user(u) for u in self._db_user.followers().users()] def retrieve_following(self): print("cached user retreiving following") self.save_following() return [self._make_user(u) for u in self._db_user.following().users()]
class RecursiveInstaUser(InstaUser, metaclass=delegation_metaclass("_target")): def __init__( self, user: InstaUser, ): self._target = user def save_followers(self): print(f"recursive save followers of {self.id()}") self._target.save_followers() followers = self._target.retrieve_followers() for i, f in enumerate(followers, 1): print( f"inner recursive save followers of {f.id()}. #{i} of {len(followers)}" ) f.save_followers() def save_following(self): print(f"recursive save following of {self.id()}") self._target.save_following() followers = self._target.retrieve_followers() for i, f in enumerate(followers, 1): print( f"inner recursive save following of {f.id()}. #{i} of {len(followers)}" ) f.save_following() def save_info(self): print(f"recursive save info of {self.id()}") self._target.save_info() self._target.save_followers() for f in self._target.retrieve_followers(): print(f"inner recursive save info of {f.id()}") f.save_info() def save_posts_info(self): print(f"recursive save posts info of {self.id()}") self._target.save_posts_info() print(f"retreive followrs result {self._target.retrieve_followers()}") for f in self._target.retrieve_followers(): print(f"inner recursive posts info of {f.id()}") f.save_posts_info()
class ScheduleConsFollowing(Following, metaclass=delegation_metaclass("_following")): # TODO: write tests ScheduleConsistentFollowing def __init__( self, user: User, following: Following, follow_schedule: FollowSchedule, unfollow_schedule: UnfollowSchedule, pgsql: PgsqlBase, ): self._following = following self._follow_schedule = follow_schedule self._unfollow_schedule = unfollow_schedule self._pgsql = pgsql self._user = user def users(self): return map( lambda u: ScheduleConsistentUser(u, self._follow_schedule, self. _unfollow_schedule, self._pgsql), self._following.users(), ) def update_following(self, users): users = list(users) self._following.update_following(users) for u in users: self._follow_schedule.mark_fulfilled(self._user, u) # TODO: mark all unfollow records as fulfilled for users not present def follow(self, user): self._following.follow(user) self._follow_schedule.mark_fulfilled(self._user, user) def unfollow(self, user): self._following.unfollow(user) self._unfollow_schedule.mark_fulfilled(self._user, user) def clean_up(self, target="fulfilled"): # TODO: implement unactive records removal pass
class PgActionsWithExpiration(Actions, metaclass=delegation_metaclass("_origin")): def __init__(self, pgsql, expiration_period: timedelta): self._expiration_period = expiration_period self._pgsql = pgsql self._origin = PgActions(pgsql) def followers_explored(self, user_id): rows = self._pgsql.exec( "SELECT date_taken FROM actions WHERE user_id = %s AND action_type = 'followers_explored'" " ORDER BY date_taken DESC LIMIT 1", (user_id, ), ) return rows and rows[0].date_taken >= (datetime.today() - self._expiration_period).date() def following_explored(self, user_id): rows = self._pgsql.exec( "SELECT date_taken FROM actions WHERE user_id = %s AND action_type = 'following_explored'" " ORDER BY date_taken DESC LIMIT 1", (user_id, ), ) return rows and rows[0].date_taken >= (datetime.today() - self._expiration_period).date() def info_saved(self, user_id): rows = self._pgsql.exec( "SELECT date_taken FROM actions WHERE user_id = %s AND action_type = 'info_saved'" " ORDER BY date_taken DESC LIMIT 1", (user_id, ), ) return rows and rows[0].date_taken >= (datetime.today() - self._expiration_period).date() def posts_info_saved(self, user_id): rows = self._pgsql.exec( "SELECT date_taken FROM actions WHERE user_id = %s AND action_type = 'posts_info_saved'" " ORDER BY date_taken DESC LIMIT 1", (user_id, ), ) return rows and rows[0].date_taken >= (datetime.today() - self._expiration_period).date()
class CachedInstaUser(InstaUser, metaclass=delegation_metaclass("_origin")): def __init__(self, user: InstaUser, db_user: User, actions: Actions, make_user: Callable[[User], InstaUser]): self._origin = user self._db_user = db_user self._actions = actions self._make_user = make_user def id(self) -> int: return self._origin.id() def retrieve_followers(self): if self._actions.followers_explored(self.id()): return [self._make_user(u) for u in self._db_user.followers().users()] return self._origin.retrieve_followers() def retrieve_following(self): if self._actions.following_explored(self.id()): return [self._make_user(u) for u in self._db_user.following().users()] return self._origin.retrieve_following()
class LazyInstaUser(InstaUser, metaclass=delegation_metaclass("_user")): def __init__(self, insta_user: InstaUser, actions: Actions, db_user: User): self._user = insta_user self._actions = actions self._db_user = db_user def id(self) -> int: return self._user.id() def save_followers(self): if not self._actions.followers_explored(self.id()): print(f"Lazy user: saving followers of {self.id()}") self._user.save_followers() self._actions.mark_followers_explored(self.id()) else: print(f"Lazy user: skipping save followers of {self.id()}") def save_following(self): if not self._actions.following_explored(self.id()): print(f"Lazy user: saving following of {self.id()}") self._user.save_following() self._actions.mark_following_explored(self.id()) else: print(f"Lazy user: skipping save following of {self.id()}") def save_info(self): if not self._actions.info_saved(self.id()): print(f"Lazy user: saving info of {self.id()}") self._user.save_info() self._actions.mark_info_saved(self.id()) else: print(f"Lazy user: skipping save info of {self.id()}") def save_posts_info(self): if not self._actions.posts_info_saved(self.id()): print(f"Lazy user: saving posts info of {self.id()}") self._user.save_posts_info() self._actions.mark_posts_info_saved(self.id()) else: print(f"Lazy user: skipping save posts info of {self.id()}")