From 32d9770b27f681708159872fdf5bf885db52c51a Mon Sep 17 00:00:00 2001 From: mtrela <mtrela@syncad.com> Date: Mon, 2 Nov 2020 12:01:31 +0100 Subject: [PATCH] Refactoring of `get_state` method --- .../sql_scripts/hive_accounts_info_view.sql | 32 +++++-- hive/server/common/helpers.py | 6 +- hive/server/condenser_api/get_state.py | 85 +++++++++---------- hive/server/condenser_api/objects.py | 4 +- 4 files changed, 71 insertions(+), 56 deletions(-) diff --git a/hive/db/sql_scripts/hive_accounts_info_view.sql b/hive/db/sql_scripts/hive_accounts_info_view.sql index 5d45f6125..4f1ef91e9 100644 --- a/hive/db/sql_scripts/hive_accounts_info_view.sql +++ b/hive/db/sql_scripts/hive_accounts_info_view.sql @@ -3,7 +3,7 @@ CREATE OR REPLACE VIEW public.hive_accounts_info_view AS SELECT ha.id, ha.name, - COALESCE(posts.post_count, 0::bigint) AS post_count, + ha.post_count, ha.created_at, ( SELECT GREATEST(ha.created_at, COALESCE(latest_post.latest_post, '1970-01-01 00:00:00'::timestamp without time zone), @@ -21,13 +21,7 @@ CREATE OR REPLACE VIEW public.hive_accounts_info_view ( SELECT max(hb.num) - 1200 * 24 * 7 AS block_limit FROM hive_blocks hb ) bl, - hive_accounts ha - LEFT JOIN LATERAL - ( - SELECT COUNT(1) AS post_count - FROM hive_posts hp - WHERE hp.counter_deleted = 0 and hp.author_id = ha.id - ) posts ON true + hive_accounts_info_view_lite ha LEFT JOIN lateral ( SELECT hp1.created_at AS latest_post @@ -53,3 +47,25 @@ CREATE OR REPLACE VIEW public.hive_accounts_info_view ) whole_votes ON true ; +DROP VIEW IF EXISTS hive_accounts_info_view_lite; +CREATE OR REPLACE VIEW public.hive_accounts_info_view_lite + AS + SELECT ha.id, + ha.name, + COALESCE(posts.post_count, 0::bigint) AS post_count, + ha.created_at, + ha.reputation, + ha.rank, + ha.following, + ha.followers, + ha.lastread_at, + ha.posting_json_metadata, + ha.json_metadata + FROM hive_accounts ha + LEFT JOIN LATERAL + ( + SELECT COUNT(1) AS post_count + FROM hive_posts hp + WHERE hp.counter_deleted = 0 and hp.author_id = ha.id + ) posts ON true + ; diff --git a/hive/server/common/helpers.py b/hive/server/common/helpers.py index 632886c07..14feebb18 100644 --- a/hive/server/common/helpers.py +++ b/hive/server/common/helpers.py @@ -66,19 +66,19 @@ def json_date(date=None): if not date or date == datetime.datetime.max: return '1969-12-31T23:59:59' return 'T'.join(str(date).split(' ')) -def get_hive_accounts_info_view_query_string(names): +def get_hive_accounts_info_view_query_string(names, lite = False): values = [] for name in names: values.append("('{}')".format( name )) values_str = ','.join(values) sql = """ SELECT * - FROM hive_accounts_info_view v + FROM {} v JOIN ( VALUES {} )T( _name ) ON v.name = T._name - """.format( values_str ) + """.format( ( 'hive_accounts_info_view_lite' if lite else 'hive_accounts_info_view' ), values_str ) return sql def last_month(): diff --git a/hive/server/condenser_api/get_state.py b/hive/server/condenser_api/get_state.py index 9d66562c1..9c475c56f 100644 --- a/hive/server/condenser_api/get_state.py +++ b/hive/server/condenser_api/get_state.py @@ -12,7 +12,9 @@ from hive.server.common.mutes import Mutes from hive.server.condenser_api.objects import ( load_accounts, load_posts, - load_posts_keyed) + load_posts_keyed, + _mute_votes, + _condenser_post_object) from hive.server.common.helpers import ( ApiError, return_error_info, @@ -30,6 +32,8 @@ from hive.server.condenser_api.methods import get_posts_by_given_sort from hive.server.hive_api.public import get_by_feed_with_reblog_impl +from hive.server.database_api.methods import find_votes_impl, VotesPresentation + log = logging.getLogger(__name__) # steemd account 'tabs' - specific post list queries @@ -131,7 +135,7 @@ async def get_state(context, path: str): author = valid_account(part[1][1:]) permlink = valid_permlink(part[2]) state['content'] = await _load_discussion(db, author, permlink) - state['accounts'] = await _load_content_accounts(db, state['content']) + state['accounts'] = await _load_content_accounts(db, state['content'], True) # ranked posts - `/sort/category` elif part[0] in POST_LIST_SORTS: @@ -205,12 +209,15 @@ def _keyed_posts(posts): def _ref(post): return post['author'] + '/' + post['permlink'] -async def _load_content_accounts(db, content): +def _ref_parent(post): + return post['parent_author'] + '/' + post['parent_permlink'] + +async def _load_content_accounts(db, content, lite = False): if not content: return {} posts = content.values() names = set(map(lambda p: p['author'], posts)) - accounts = await load_accounts(db, names) + accounts = await load_accounts(db, names, lite) return {a['name']: a for a in accounts} async def _load_account(db, name): @@ -235,47 +242,39 @@ async def _child_ids(db, parent_ids): async def _load_discussion(db, author, permlink): """Load a full discussion thread.""" - root_id = await cursor.get_post_id(db, author, permlink) - if not root_id: - return {} - # build `ids` list and `tree` map - ids = [] - tree = {} - todo = [root_id] - while todo: - ids.extend(todo) - rows = await _child_ids(db, todo) - todo = [] - for pid, cids in rows: - tree[pid] = cids - todo.extend(cids) - - # load all post objects, build ref-map - posts = await load_posts_keyed(db, ids) - - # remove posts/comments from muted accounts + sql = "SELECT * FROM get_discussion('{}','{}')".format( author, permlink) + sql_result = await db.query_all(sql) + muted_accounts = Mutes.all() - rem_pids = [] - for pid, post in posts.items(): - if post['author'] in muted_accounts: - rem_pids.append(pid) - for pid in rem_pids: - if pid in posts: - del posts[pid] - if pid in tree: - rem_pids.extend(tree[pid]) - - refs = {pid: _ref(post) for pid, post in posts.items()} - - # add child refs to parent posts - for pid, post in posts.items(): - if pid in tree: - post['replies'] = [refs[cid] for cid in tree[pid] - if cid in refs] - - # return all nodes keyed by ref - return {refs[pid]: post for pid, post in posts.items()} + posts = [] + posts_by_id = {} + replies = {} + + for row in sql_result: + post = _condenser_post_object(row) + + if post['author'] not in muted_accounts: + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.CondenserApi) + post['active_votes'] = _mute_votes(post['active_votes'], muted_accounts) + posts.append(post) + + parent_key = _ref_parent(post) + _key = _ref(post) + if parent_key not in replies: + replies[parent_key] = [] + replies[parent_key].append(_key) + + for post in posts: + _key = _ref(post) + if _key in replies: + replies[_key].sort() + post['replies'] = replies[_key] + + for post in posts: + posts_by_id[_ref(post)] = post + + return posts_by_id @cached(ttl=1800, timeout=1200) async def _get_feed_price(db): diff --git a/hive/server/condenser_api/objects.py b/hive/server/condenser_api/objects.py index 0f5222843..607c3402c 100644 --- a/hive/server/condenser_api/objects.py +++ b/hive/server/condenser_api/objects.py @@ -13,9 +13,9 @@ log = logging.getLogger(__name__) # Building of legacy account objects -async def load_accounts(db, names): +async def load_accounts(db, names, lite = False): """`get_accounts`-style lookup for `get_state` compat layer.""" - sql = get_hive_accounts_info_view_query_string( names ) + sql = get_hive_accounts_info_view_query_string( names, lite ) rows = await db.query_all(sql, names=tuple(names)) return [_condenser_account_object(row) for row in rows] -- GitLab