From 76d51a4cefabaf10368b11e56bf6fd08208ea2e8 Mon Sep 17 00:00:00 2001 From: ABW <andrzejl@syncad.com> Date: Thu, 10 Sep 2020 21:21:35 +0200 Subject: [PATCH] [ABW]: SQL function get_account renamed find_account_id vote related views/types/functions extended by id since database_api requires it new SQL function to cover find_votes functionality neither voter nor post is mandatory in list_votes calls fixed internal _get_post_id in bridge_api find_votes_impl no longer requires full context, just what it actually uses: db find_votes_impl no longer checks passed arguments, only its official API version does list_votes_impl removed, only its official version is needed official API find_votes/list_votes now properly pack response in dictionary with 'votes' list --- hive/db/schema.py | 231 ++++++++++++++++----------- hive/server/bridge_api/cursor.py | 2 +- hive/server/bridge_api/methods.py | 8 +- hive/server/bridge_api/objects.py | 2 +- hive/server/bridge_api/thread.py | 4 +- hive/server/condenser_api/methods.py | 10 +- hive/server/condenser_api/objects.py | 4 +- hive/server/database_api/methods.py | 55 ++----- tests/tests_api | 2 +- 9 files changed, 169 insertions(+), 149 deletions(-) diff --git a/hive/db/schema.py b/hive/db/schema.py index 28f0b96eb..ad5e2432a 100644 --- a/hive/db/schema.py +++ b/hive/db/schema.py @@ -466,6 +466,60 @@ def setup(db): sql = "CREATE INDEX hive_communities_ft1 ON hive_communities USING GIN (to_tsvector('english', title || ' ' || about))" db.query(sql) + sql = """ + DROP FUNCTION IF EXISTS find_comment_id(character varying, character varying, boolean) + ; + CREATE OR REPLACE FUNCTION find_comment_id( + in _author hive_accounts.name%TYPE, + in _permlink hive_permlink_data.permlink%TYPE, + in _check boolean) + RETURNS INT + LANGUAGE 'plpgsql' + AS + $function$ + DECLARE + post_id INT; + BEGIN + SELECT INTO post_id COALESCE( (SELECT hp.id + FROM hive_posts hp + JOIN hive_accounts ha ON ha.id = hp.author_id + JOIN hive_permlink_data hpd ON hpd.id = hp.permlink_id + WHERE ha.name = _author AND hpd.permlink = _permlink AND hp.counter_deleted = 0 + ), 0 ); + IF _check AND (_author <> '' OR _permlink <> '') AND post_id = 0 THEN + RAISE EXCEPTION 'Post %/% does not exist', _author, _permlink; + END IF; + RETURN post_id; + END + $function$ + ; + """ + db.query_no_return(sql) + + sql = """ + DROP FUNCTION IF EXISTS find_account_id(character varying, boolean) + ; + CREATE OR REPLACE FUNCTION find_account_id( + in _account hive_accounts.name%TYPE, + in _check boolean) + RETURNS INT + LANGUAGE 'plpgsql' + AS + $function$ + DECLARE + account_id INT; + BEGIN + SELECT INTO account_id COALESCE( ( SELECT id FROM hive_accounts WHERE name=_account ), 0 ); + IF _check AND account_id = 0 THEN + RAISE EXCEPTION 'Account % does not exist', _account; + END IF; + RETURN account_id; + END + $function$ + ; + """ + db.query_no_return(sql) + sql = """ DROP FUNCTION if exists process_hive_post_operation(character varying,character varying,character varying,character varying,timestamp without time zone,timestamp without time zone) ; @@ -859,6 +913,7 @@ def setup(db): CREATE OR REPLACE VIEW hive_votes_view AS SELECT + hv.id, hv.voter_id as voter_id, ha_a.name as author, hpd.permlink as permlink, @@ -885,6 +940,7 @@ def setup(db): DROP TYPE IF EXISTS database_api_vote CASCADE; CREATE TYPE database_api_vote AS ( + id BIGINT, voter VARCHAR(16), author VARCHAR(16), permlink VARCHAR(255), @@ -896,30 +952,47 @@ def setup(db): reputation FLOAT4 ); - DROP FUNCTION IF EXISTS get_account(character varying, boolean); - - CREATE OR REPLACE FUNCTION get_account( - in _account hive_accounts.name%TYPE, - in _check boolean) - RETURNS INT + DROP FUNCTION IF EXISTS find_votes( character varying, character varying ) + ; + CREATE OR REPLACE FUNCTION public.find_votes + ( + in _AUTHOR hive_accounts.name%TYPE, + in _PERMLINK hive_permlink_data.permlink%TYPE + ) + RETURNS SETOF database_api_vote LANGUAGE 'plpgsql' AS $function$ - DECLARE - account_id INT; + DECLARE _POST_ID INT; BEGIN - SELECT INTO account_id COALESCE( ( SELECT id FROM hive_accounts WHERE name=_account ), 0 ); - IF _check AND account_id = 0 THEN - RAISE EXCEPTION 'Account % does not exist', _account; - END IF; + _POST_ID = find_comment_id( _AUTHOR, _PERMLINK, True); - RETURN account_id; - END - $function$ - ; + RETURN QUERY + ( + SELECT + v.id, + v.voter, + v.author, + v.permlink, + v.weight, + v.rshares, + v.percent, + v.last_update, + v.num_changes, + v.reputation + FROM + hive_votes_view v + WHERE + v.post_id = _POST_ID + ORDER BY + voter_id + ); - DROP FUNCTION IF EXISTS list_votes_by_voter_comment( character varying, character varying, character varying, int ); + END + $function$; + DROP FUNCTION IF EXISTS list_votes_by_voter_comment( character varying, character varying, character varying, int ) + ; CREATE OR REPLACE FUNCTION public.list_votes_by_voter_comment ( in _VOTER hive_accounts.name%TYPE, @@ -935,38 +1008,39 @@ def setup(db): DECLARE _POST_ID INT; BEGIN - _VOTER_ID = get_account( _VOTER, true ); - _POST_ID = find_comment_id( _AUTHOR, _PERMLINK, True); + _VOTER_ID = find_account_id( _VOTER, _VOTER != '' ); + _POST_ID = find_comment_id( _AUTHOR, _PERMLINK, _AUTHOR != '' OR _PERMLINK != '' ); RETURN QUERY ( - SELECT - v.voter, - v.author, - v.permlink, - v.weight, - v.rshares, - v.percent, - v.last_update, - v.num_changes, - v.reputation - FROM - hive_votes_view v - WHERE - ( v.voter_id = _VOTER_ID and v.post_id >= _POST_ID ) - OR - ( v.voter_id > _VOTER_ID ) - ORDER BY - voter_id, - post_id - LIMIT _LIMIT + SELECT + v.id, + v.voter, + v.author, + v.permlink, + v.weight, + v.rshares, + v.percent, + v.last_update, + v.num_changes, + v.reputation + FROM + hive_votes_view v + WHERE + ( v.voter_id = _VOTER_ID and v.post_id >= _POST_ID ) + OR + ( v.voter_id > _VOTER_ID ) + ORDER BY + voter_id, + post_id + LIMIT _LIMIT ); END $function$; - DROP FUNCTION IF EXISTS list_votes_by_comment_voter( character varying, character varying, character varying, int ); - + DROP FUNCTION IF EXISTS list_votes_by_comment_voter( character varying, character varying, character varying, int ) + ; CREATE OR REPLACE FUNCTION public.list_votes_by_comment_voter ( in _VOTER hive_accounts.name%TYPE, @@ -982,31 +1056,32 @@ def setup(db): DECLARE _POST_ID INT; BEGIN - _VOTER_ID = get_account( _VOTER, true ); - _POST_ID = find_comment_id( _AUTHOR, _PERMLINK, True); + _VOTER_ID = find_account_id( _VOTER, _VOTER != '' ); + _POST_ID = find_comment_id( _AUTHOR, _PERMLINK, _AUTHOR != '' OR _PERMLINK != '' ); RETURN QUERY ( - SELECT - v.voter, - v.author, - v.permlink, - v.weight, - v.rshares, - v.percent, - v.last_update, - v.num_changes, - v.reputation - FROM - hive_votes_view v - WHERE - ( v.post_id = _POST_ID and v.voter_id >= _VOTER_ID ) - OR - ( v.post_id > _POST_ID ) - ORDER BY - post_id, - voter_id - LIMIT _LIMIT + SELECT + v.id, + v.voter, + v.author, + v.permlink, + v.weight, + v.rshares, + v.percent, + v.last_update, + v.num_changes, + v.reputation + FROM + hive_votes_view v + WHERE + ( v.post_id = _POST_ID and v.voter_id >= _VOTER_ID ) + OR + ( v.post_id > _POST_ID ) + ORDER BY + post_id, + voter_id + LIMIT _LIMIT ); END @@ -1014,36 +1089,6 @@ def setup(db): """ db.query_no_return(sql) - sql = """ - DROP FUNCTION IF EXISTS find_comment_id(character varying, character varying, boolean) - ; - CREATE OR REPLACE FUNCTION find_comment_id( - in _author hive_accounts.name%TYPE, - in _permlink hive_permlink_data.permlink%TYPE, - in _check boolean) - RETURNS INT - LANGUAGE 'plpgsql' - AS - $function$ - DECLARE - post_id INT; - BEGIN - SELECT INTO post_id COALESCE( (SELECT hp.id - FROM hive_posts hp - JOIN hive_accounts ha ON ha.id = hp.author_id - JOIN hive_permlink_data hpd ON hpd.id = hp.permlink_id - WHERE ha.name = _author AND hpd.permlink = _permlink AND hp.counter_deleted = 0 - ), 0 ); - IF _check AND (_author <> '' OR _permlink <> '') AND post_id = 0 THEN - RAISE EXCEPTION 'Post %/% does not exist', _author, _permlink; - END IF; - RETURN post_id; - END - $function$ - ; - """ - db.query_no_return(sql) - sql = """ DROP TYPE IF EXISTS database_api_post CASCADE; CREATE TYPE database_api_post AS ( diff --git a/hive/server/bridge_api/cursor.py b/hive/server/bridge_api/cursor.py index c24c27e30..dc046a863 100644 --- a/hive/server/bridge_api/cursor.py +++ b/hive/server/bridge_api/cursor.py @@ -21,7 +21,7 @@ async def _get_post_id(db, author, permlink): INNER JOIN hive_accounts ha_a ON ha_a.id = hp.author_id INNER JOIN hive_permlink_data hpd_p ON hpd_p.id = hp.permlink_id WHERE ha_a.name = :author AND hpd_p.permlink = :permlink""" - post_id = await db.query_one(sql, a=author, p=permlink) + post_id = await db.query_one(sql, author=author, permlink=permlink) assert post_id, 'invalid author/permlink' return post_id diff --git a/hive/server/bridge_api/methods.py b/hive/server/bridge_api/methods.py index 970629487..40c7e5899 100644 --- a/hive/server/bridge_api/methods.py +++ b/hive/server/bridge_api/methods.py @@ -109,7 +109,7 @@ async def get_post(context, author, permlink, observer=None): result = await db.query_all(sql, author=author, permlink=permlink) assert len(result) == 1, 'invalid author/permlink or post not found in cache' post = _bridge_post_object(result[0]) - post['active_votes'] = await find_votes_impl({'db':db}, author, permlink, VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, author, permlink, VotesPresentation.BridgeApi) post = await append_statistics_to_post(post, result[0], False, blacklists_for_user) return post @@ -213,7 +213,7 @@ async def get_ranked_posts(context, sort, start_author='', start_permlink='', pinned_result = await db.query_all(pinned_sql, author=start_author, limit=limit, tag=tag, permlink=start_permlink, community_name=tag, observer=observer) for row in pinned_result: post = _bridge_post_object(row) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.BridgeApi) post = await append_statistics_to_post(post, row, True, blacklists_for_user) limit = limit - 1 posts.append(post) @@ -222,7 +222,7 @@ async def get_ranked_posts(context, sort, start_author='', start_permlink='', sql_result = await db.query_all(sql, author=start_author, limit=limit, tag=tag, permlink=start_permlink, community_name=tag, observer=observer) for row in sql_result: post = _bridge_post_object(row) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.BridgeApi) post = await append_statistics_to_post(post, row, False, blacklists_for_user) if post['post_id'] in pinned_post_ids: continue @@ -314,7 +314,7 @@ async def get_account_posts(context, sort, account, start_author='', start_perml sql_result = await db.query_all(sql, account=account, author=start_author, permlink=start_permlink, limit=limit) for row in sql_result: post = _bridge_post_object(row) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.BridgeApi) post = await append_statistics_to_post(post, row, False, blacklists_for_user) posts.append(post) return posts diff --git a/hive/server/bridge_api/objects.py b/hive/server/bridge_api/objects.py index 1f7ddbbcd..121d6d90b 100644 --- a/hive/server/bridge_api/objects.py +++ b/hive/server/bridge_api/objects.py @@ -100,7 +100,7 @@ async def load_posts_keyed(db, ids, truncate_body=0): row['author_rep'] = author['reputation'] post = _bridge_post_object(row, truncate_body=truncate_body) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.BridgeApi) post['blacklists'] = Mutes.lists(post['author'], author['reputation']) diff --git a/hive/server/bridge_api/thread.py b/hive/server/bridge_api/thread.py index 145534810..be6f5950d 100644 --- a/hive/server/bridge_api/thread.py +++ b/hive/server/bridge_api/thread.py @@ -95,7 +95,7 @@ async def get_discussion(context, author, permlink, observer=None): root_id = rows[0]['id'] all_posts = {} root_post = _bridge_post_object(rows[0]) - root_post['active_votes'] = await find_votes_impl({'db':db}, rows[0]['author'], rows[0]['permlink'], VotesPresentation.BridgeApi) + root_post['active_votes'] = await find_votes_impl(db, rows[0]['author'], rows[0]['permlink'], VotesPresentation.BridgeApi) root_post = await append_statistics_to_post(root_post, rows[0], False, blacklists_for_user) root_post['replies'] = [] all_posts[root_id] = root_post @@ -108,7 +108,7 @@ async def get_discussion(context, author, permlink, observer=None): parent_to_children_id_map[parent_id] = [] parent_to_children_id_map[parent_id].append(rows[index]['id']) post = _bridge_post_object(rows[index]) - post['active_votes'] = await find_votes_impl({'db':db}, rows[index]['author'], rows[index]['permlink'], VotesPresentation.BridgeApi) + post['active_votes'] = await find_votes_impl(db, rows[index]['author'], rows[index]['permlink'], VotesPresentation.BridgeApi) post = await append_statistics_to_post(post, rows[index], False, blacklists_for_user) post['replies'] = [] all_posts[post['post_id']] = post diff --git a/hive/server/condenser_api/methods.py b/hive/server/condenser_api/methods.py index bf3375c65..88541517a 100644 --- a/hive/server/condenser_api/methods.py +++ b/hive/server/condenser_api/methods.py @@ -154,7 +154,7 @@ async def get_content(context, author: str, permlink: str, observer=None): if result: result = dict(result[0]) post = _condenser_post_object(result, 0) - post['active_votes'] = await find_votes_impl(context, author, permlink, VotesPresentation.CondenserApi) + post['active_votes'] = await find_votes_impl(db, author, permlink, VotesPresentation.CondenserApi) if not observer: post['active_votes'] = _mute_votes(post['active_votes'], Mutes.all()) else: @@ -272,7 +272,7 @@ async def get_discussions_by(discussion_type, context, start_author: str = '', posts = [] for row in result: post = _condenser_post_object(row, truncate_body) - post['active_votes'] = await find_votes_impl(context, post['author'], post['permlink'], VotesPresentation.DatabaseApi ) + post['active_votes'] = await find_votes_impl(db, post['author'], post['permlink'], VotesPresentation.DatabaseApi ) post['active_votes'] = _mute_votes(post['active_votes'], Mutes.all()) posts.append(post) #posts = await resultset_to_posts(db=db, resultset=result, truncate_body=truncate_body) @@ -381,7 +381,7 @@ async def get_discussions_by_blog(context, tag: str = None, start_author: str = for row in result: row = dict(row) post = _condenser_post_object(row, truncate_body=truncate_body) - post['active_votes'] = await find_votes_impl(context, post['author'], post['permlink'], VotesPresentation.CondenserApi) + post['active_votes'] = await find_votes_impl(db, post['author'], post['permlink'], VotesPresentation.CondenserApi) post['active_votes'] = _mute_votes(post['active_votes'], Mutes.all()) #posts_by_id[row['post_id']] = post posts_by_id.append(post) @@ -439,7 +439,7 @@ async def get_discussions_by_comments(context, start_author: str = None, start_p for row in result: row = dict(row) post = _condenser_post_object(row, truncate_body=truncate_body) - post['active_votes'] = await find_votes_impl(context, post['author'], post['permlink'], VotesPresentation.CondenserApi) + post['active_votes'] = await find_votes_impl(db, post['author'], post['permlink'], VotesPresentation.CondenserApi) post['active_votes'] = _mute_votes(post['active_votes'], Mutes.all()) posts.append(post) @@ -592,4 +592,4 @@ async def get_active_votes(context, author: str, permlink: str): valid_permlink(permlink) db = context['db'] - return await find_votes_impl( {'db':db}, author, permlink, VotesPresentation.ActiveVotes ) + return await find_votes_impl( db, author, permlink, VotesPresentation.ActiveVotes ) diff --git a/hive/server/condenser_api/objects.py b/hive/server/condenser_api/objects.py index 9fef75b65..6d25aefdf 100644 --- a/hive/server/condenser_api/objects.py +++ b/hive/server/condenser_api/objects.py @@ -89,7 +89,7 @@ async def load_posts_keyed(db, ids, truncate_body=0): row['author_rep'] = author_reps[row['author']] post = _condenser_post_object(row, truncate_body=truncate_body) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.CondenserApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.CondenserApi) posts_by_id[row['id']] = post return posts_by_id @@ -139,7 +139,7 @@ async def resultset_to_posts(db, resultset, truncate_body=0): row = dict(row) row['author_rep'] = author_reps[row['author']] post = _condenser_post_object(row, truncate_body=truncate_body) - post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.CondenserApi) + post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.CondenserApi) posts.append(post) return posts diff --git a/hive/server/database_api/methods.py b/hive/server/database_api/methods.py index bf906e013..473b2789d 100644 --- a/hive/server/database_api/methods.py +++ b/hive/server/database_api/methods.py @@ -172,7 +172,7 @@ def api_vote_info(rows, votes_presentation): ret = [] for row in rows: if votes_presentation == VotesPresentation.DatabaseApi: - ret.append(dict(voter = row.voter, author = row.author, permlink = row.permlink, + ret.append(dict(id = row.id, voter = row.voter, author = row.author, permlink = row.permlink, weight = row.weight, rshares = row.rshares, vote_percent = row.percent, last_update = json_date(row.last_update), num_changes = row.num_changes)) elif votes_presentation == VotesPresentation.CondenserApi: @@ -188,35 +188,20 @@ def api_vote_info(rows, votes_presentation): return ret @return_error_info -async def find_votes_impl(context, author: str, permlink: str, votes_presentation): +async def find_votes_impl(db, author: str, permlink: str, votes_presentation): + sql = "SELECT * FROM find_votes(:author,:permlink)" + rows = await db.query_all(sql, author=author, permlink=permlink) + return api_vote_info(rows, votes_presentation) + +@return_error_info +async def find_votes(context, author: str, permlink: str): """ Returns all votes for the given post """ valid_account(author) valid_permlink(permlink) - db = context['db'] - sql = """ - SELECT - voter, - author, - permlink, - weight, - rshares, - percent, - last_update, - num_changes, - reputation - FROM - hive_votes_view - WHERE - author = :author AND permlink = :permlink - ORDER BY - voter_id - """ - - rows = await db.query_all(sql, author=author, permlink=permlink) - return api_vote_info(rows, votes_presentation) + return { 'votes': await find_votes_impl(context['db'], author, permlink, VotesPresentation.DatabaseApi) } @return_error_info -async def list_votes_impl(context, start: list, limit: int, order: str, votes_presentation): +async def list_votes(context, start: list, limit: int, order: str): """ Returns all votes, starting with the specified voter and/or author and permlink. """ supported_order_list = ["by_comment_voter", "by_voter_comment"] assert order in supported_order_list, "Order {} is not supported".format(order) @@ -224,21 +209,11 @@ async def list_votes_impl(context, start: list, limit: int, order: str, votes_pr assert len(start) == 3, "Expecting 3 elements in start array" db = context['db'] - sql="" - if order == "by_voter_comment": - sql = "select * from list_votes_by_voter_comment( '{}', '{}', '{}', {} )".format( start[0], start[1], start[2], limit ) + sql = "SELECT * FROM list_votes_by_voter_comment(:voter,:author,:permlink,:limit)" + rows = await db.query_all(sql, voter=start[0], author=start[1], permlink=start[2], limit=limit) else: - sql = "select * from list_votes_by_comment_voter( '{}', '{}', '{}', {} )".format( start[2], start[0], start[1], limit ) - - rows = await db.query_all(sql) - - return api_vote_info(rows, votes_presentation) - -@return_error_info -async def find_votes(context, author: str, permlink: str): - return await find_votes_impl( context, author, permlink, VotesPresentation.DatabaseApi) + sql = "SELECT * FROM list_votes_by_comment_voter(:voter,:author,:permlink,:limit)" + rows = await db.query_all(sql, voter=start[2], author=start[0], permlink=start[1], limit=limit) + return { 'votes': api_vote_info(rows, VotesPresentation.DatabaseApi) } -@return_error_info -async def list_votes(context, start: list, limit: int, order: str): - return await list_votes_impl( context, start, limit, order, VotesPresentation.DatabaseApi) diff --git a/tests/tests_api b/tests/tests_api index 4216ec21d..37ab1a0ae 160000 --- a/tests/tests_api +++ b/tests/tests_api @@ -1 +1 @@ -Subproject commit 4216ec21d977cb6ee08f4f655b3cf40165f7292d +Subproject commit 37ab1a0aed778c363852c9a2b0caed5b3e06d438 -- GitLab