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