From 648ce0579afecdc57efdf6d530eccdd7243d7022 Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger Date: Mon, 19 Dec 2022 16:33:08 +0100 Subject: [PATCH] replaced asset search with get_asset_by_cid Signed-off-by: Lorenz Herzberger --- planetmint/backend/query.py | 6 ++++ planetmint/backend/tarantool/init.lua | 14 +++++++-- planetmint/backend/tarantool/query.py | 7 ++++- planetmint/lib.py | 7 +++++ planetmint/web/routes.py | 2 +- planetmint/web/views/assets.py | 32 ++++--------------- tests/web/test_assets.py | 45 ++------------------------- 7 files changed, 39 insertions(+), 74 deletions(-) diff --git a/planetmint/backend/query.py b/planetmint/backend/query.py index 024c240..bf08148 100644 --- a/planetmint/backend/query.py +++ b/planetmint/backend/query.py @@ -90,6 +90,12 @@ def get_transaction(connection, transaction_id): raise NotImplementedError +@singledispatch +def get_transactions_by_asset(connection, asset): + """Get a transaction by id.""" + + raise NotImplementedError + @singledispatch def get_transactions(connection, transactions_ids) -> list[DbTransaction]: """Get a transaction from the transactions table. diff --git a/planetmint/backend/tarantool/init.lua b/planetmint/backend/tarantool/init.lua index 3a46ddb..044dce3 100644 --- a/planetmint/backend/tarantool/init.lua +++ b/planetmint/backend/tarantool/init.lua @@ -34,12 +34,20 @@ function init() if_not_exists = true, parts = {{ field = 'id', type = 'string' }} }) - transactions:create_index('transactions_by_asset', { + transactions:create_index('transactions_by_asset_id', { if_not_exists = true, + unique = false, + parts = { + { field = 'assets[*].id', type = 'string', is_nullable = true } + } + }) + transactions:create_index('transactions_by_asset_cid', { + if_not_exists = true, + unique = false, parts = { - { field = 'assets[*].id', type = 'string', is_nullable = true }, { field = 'assets[*].data', type = 'string', is_nullable = true } - }}) + } + }) transactions:create_index('spending_transaction_by_id_and_output_index', { if_not_exists = true, parts = { diff --git a/planetmint/backend/tarantool/query.py b/planetmint/backend/tarantool/query.py index 8793e4a..a9f6fac 100644 --- a/planetmint/backend/tarantool/query.py +++ b/planetmint/backend/tarantool/query.py @@ -54,6 +54,12 @@ def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]: def get_transaction(connection, tx_id: str) -> DbTransaction: return NotImplemented +@register_query(TarantoolDBConnection) +def get_transactions_by_asset(connection, asset: str) -> list[DbTransaction]: + txs = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset, index="transactions_by_asset_cid")) + tx_ids = [tx[0] for tx in txs] + return get_complete_transactions_by_ids(connection, tx_ids) + def store_transaction_outputs(connection, output: Output, index: int) -> str: output_id = uuid4().hex @@ -117,7 +123,6 @@ def get_asset(connection, asset_id: str) -> Asset: _data = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset_id, index=TARANT_INDEX_TX_BY_ASSET_ID)) return Asset.from_dict(_data[0]) - @register_query(TarantoolDBConnection) def get_assets(connection, assets_ids: list) -> list[Asset]: _returned_data = [] diff --git a/planetmint/lib.py b/planetmint/lib.py index 68b7cb6..e9ea88b 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -14,6 +14,7 @@ import json import rapidjson import requests +from itertools import chain from collections import namedtuple, OrderedDict from uuid import uuid4 from hashlib import sha3_256 @@ -451,6 +452,12 @@ class Planetmint(object): """ return backend.query.get_assets(self.connection, asset_ids) + def get_assets_by_cid(self, asset_cid) -> list[dict]: + asset_txs = backend.query.get_transactions_by_asset(self.connection, asset_cid) + # flatten and return all found assets + return list(chain.from_iterable([Asset.list_to_dict(tx.assets) for tx in asset_txs])) + + def get_metadata(self, txn_ids) -> list[MetaData]: """Return a list of metadata that match the transaction ids (txn_ids) diff --git a/planetmint/web/routes.py b/planetmint/web/routes.py index 3579c2e..b17a107 100644 --- a/planetmint/web/routes.py +++ b/planetmint/web/routes.py @@ -31,7 +31,7 @@ def r(*args, **kwargs): ROUTES_API_V1 = [ r("/", info.ApiV1Index), - r("assets/", assets.AssetListApi), + r("assets/", assets.AssetListApi), r("metadata/", metadata.MetadataApi), r("blocks/", blocks.BlockApi), r("blocks/latest", blocks.LatestBlock), diff --git a/planetmint/web/views/assets.py b/planetmint/web/views/assets.py index f1a04d7..a106357 100644 --- a/planetmint/web/views/assets.py +++ b/planetmint/web/views/assets.py @@ -9,7 +9,7 @@ For more information please refer to the documentation: http://planetmint.io/htt """ import logging -from flask_restful import reqparse, Resource +from flask_restful import Resource from flask import current_app from planetmint.backend.exceptions import OperationError from planetmint.web.views.base import make_error @@ -18,34 +18,14 @@ logger = logging.getLogger(__name__) class AssetListApi(Resource): - def get(self): - """API endpoint to perform a text search on the assets. - - Args: - search (str): Text search string to query the text index - limit (int, optional): Limit the number of returned documents. - - Return: - A list of assets that match the query. - """ - parser = reqparse.RequestParser() - parser.add_argument("search", type=str, required=True) - parser.add_argument("limit", type=int) - args = parser.parse_args() - - if not args["search"]: - return make_error(400, "text_search cannot be empty") - if not args["limit"]: - # if the limit is not specified do not pass None to `text_search` - del args["limit"] - + def get(self, cid: str): pool = current_app.config["bigchain_pool"] - + with pool() as planet: - assets = planet.text_search(**args) - + assets = planet.get_assets_by_cid(cid) + try: # This only works with MongoDB as the backend - return list(assets) + return assets except OperationError as e: return make_error(400, "({}): {}".format(type(e).__name__, e)) diff --git a/tests/web/test_assets.py b/tests/web/test_assets.py index 366b487..d027daa 100644 --- a/tests/web/test_assets.py +++ b/tests/web/test_assets.py @@ -11,56 +11,15 @@ from ipld import marshal, multihash ASSETS_ENDPOINT = "/api/v1/assets/" -def test_get_assets_with_empty_text_search(client): - res = client.get(ASSETS_ENDPOINT + "?search=") - assert res.json == {"status": 400, "message": "text_search cannot be empty"} - assert res.status_code == 400 - - -def test_get_assets_with_missing_text_search(client): - res = client.get(ASSETS_ENDPOINT) - assert res.status_code == 400 - - @pytest.mark.bdb def test_get_assets_tendermint(client, b, alice): - - # test returns empty list when no assets are found - res = client.get(ASSETS_ENDPOINT + "?search=abc") - assert res.json == [] - assert res.status_code == 200 - # create asset assets = [{"data": multihash(marshal({"msg": "abc"}))}] tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=assets).sign([alice.private_key]) b.store_bulk_transactions([tx]) - # test that asset is returned - res = client.get(ASSETS_ENDPOINT + "?search=" + assets[0]["data"]) - assert res.status_code == 200 - assert len(res.json) == 1 - assert res.json[0] == {"data": assets[0]["data"], "id": tx.id} - - -@pytest.mark.bdb -def test_get_assets_limit_tendermint(client, b, alice): - - # create two assets - assets1 = [{"data": multihash(marshal({"msg": "abc 1"}))}] - assets2 = [{"data": multihash(marshal({"msg": "abc 2"}))}] - tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=assets1).sign([alice.private_key]) - tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=assets2).sign([alice.private_key]) - - b.store_bulk_transactions([tx1]) - b.store_bulk_transactions([tx2]) - - # test that both assets are returned without limit - res = client.get(ASSETS_ENDPOINT + "?search=" + assets1[0]["data"]) - assert res.status_code == 200 - assert len(res.json) == 1 - - # test that only one asset is returned when using limit=1 - res = client.get(ASSETS_ENDPOINT + "?search=" + assets1[0]["data"] + "&limit=1") + res = client.get(ASSETS_ENDPOINT + assets[0]["data"]) assert res.status_code == 200 assert len(res.json) == 1 + assert res.json[0] == {"data": assets[0]["data"]}