replaced asset search with get_asset_by_cid

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2022-12-19 16:33:08 +01:00
parent d73bb15708
commit 648ce0579a
No known key found for this signature in database
GPG Key ID: FA5EE906EB55316A
7 changed files with 39 additions and 74 deletions

View File

@ -90,6 +90,12 @@ def get_transaction(connection, transaction_id):
raise NotImplementedError raise NotImplementedError
@singledispatch
def get_transactions_by_asset(connection, asset):
"""Get a transaction by id."""
raise NotImplementedError
@singledispatch @singledispatch
def get_transactions(connection, transactions_ids) -> list[DbTransaction]: def get_transactions(connection, transactions_ids) -> list[DbTransaction]:
"""Get a transaction from the transactions table. """Get a transaction from the transactions table.

View File

@ -34,12 +34,20 @@ function init()
if_not_exists = true, if_not_exists = true,
parts = {{ field = 'id', type = 'string' }} parts = {{ field = 'id', type = 'string' }}
}) })
transactions:create_index('transactions_by_asset', { transactions:create_index('transactions_by_asset_id', {
if_not_exists = true, 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 = { parts = {
{ field = 'assets[*].id', type = 'string', is_nullable = true },
{ field = 'assets[*].data', type = 'string', is_nullable = true } { field = 'assets[*].data', type = 'string', is_nullable = true }
}}) }
})
transactions:create_index('spending_transaction_by_id_and_output_index', { transactions:create_index('spending_transaction_by_id_and_output_index', {
if_not_exists = true, if_not_exists = true,
parts = { parts = {

View File

@ -54,6 +54,12 @@ def get_outputs_by_tx_id(connection, tx_id: str) -> list[Output]:
def get_transaction(connection, tx_id: str) -> DbTransaction: def get_transaction(connection, tx_id: str) -> DbTransaction:
return NotImplemented 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: def store_transaction_outputs(connection, output: Output, index: int) -> str:
output_id = uuid4().hex 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)) _data = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset_id, index=TARANT_INDEX_TX_BY_ASSET_ID))
return Asset.from_dict(_data[0]) return Asset.from_dict(_data[0])
@register_query(TarantoolDBConnection) @register_query(TarantoolDBConnection)
def get_assets(connection, assets_ids: list) -> list[Asset]: def get_assets(connection, assets_ids: list) -> list[Asset]:
_returned_data = [] _returned_data = []

View File

@ -14,6 +14,7 @@ import json
import rapidjson import rapidjson
import requests import requests
from itertools import chain
from collections import namedtuple, OrderedDict from collections import namedtuple, OrderedDict
from uuid import uuid4 from uuid import uuid4
from hashlib import sha3_256 from hashlib import sha3_256
@ -451,6 +452,12 @@ class Planetmint(object):
""" """
return backend.query.get_assets(self.connection, asset_ids) 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]: def get_metadata(self, txn_ids) -> list[MetaData]:
"""Return a list of metadata that match the transaction ids (txn_ids) """Return a list of metadata that match the transaction ids (txn_ids)

View File

@ -31,7 +31,7 @@ def r(*args, **kwargs):
ROUTES_API_V1 = [ ROUTES_API_V1 = [
r("/", info.ApiV1Index), r("/", info.ApiV1Index),
r("assets/", assets.AssetListApi), r("assets/<string:cid>", assets.AssetListApi),
r("metadata/", metadata.MetadataApi), r("metadata/", metadata.MetadataApi),
r("blocks/<int:block_id>", blocks.BlockApi), r("blocks/<int:block_id>", blocks.BlockApi),
r("blocks/latest", blocks.LatestBlock), r("blocks/latest", blocks.LatestBlock),

View File

@ -9,7 +9,7 @@ For more information please refer to the documentation: http://planetmint.io/htt
""" """
import logging import logging
from flask_restful import reqparse, Resource from flask_restful import Resource
from flask import current_app from flask import current_app
from planetmint.backend.exceptions import OperationError from planetmint.backend.exceptions import OperationError
from planetmint.web.views.base import make_error from planetmint.web.views.base import make_error
@ -18,34 +18,14 @@ logger = logging.getLogger(__name__)
class AssetListApi(Resource): class AssetListApi(Resource):
def get(self): def get(self, cid: str):
"""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"]
pool = current_app.config["bigchain_pool"] pool = current_app.config["bigchain_pool"]
with pool() as planet: with pool() as planet:
assets = planet.text_search(**args) assets = planet.get_assets_by_cid(cid)
try: try:
# This only works with MongoDB as the backend # This only works with MongoDB as the backend
return list(assets) return assets
except OperationError as e: except OperationError as e:
return make_error(400, "({}): {}".format(type(e).__name__, e)) return make_error(400, "({}): {}".format(type(e).__name__, e))

View File

@ -11,56 +11,15 @@ from ipld import marshal, multihash
ASSETS_ENDPOINT = "/api/v1/assets/" 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 @pytest.mark.bdb
def test_get_assets_tendermint(client, b, alice): 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 # create asset
assets = [{"data": multihash(marshal({"msg": "abc"}))}] assets = [{"data": multihash(marshal({"msg": "abc"}))}]
tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=assets).sign([alice.private_key]) tx = Create.generate([alice.public_key], [([alice.public_key], 1)], assets=assets).sign([alice.private_key])
b.store_bulk_transactions([tx]) b.store_bulk_transactions([tx])
# test that asset is returned res = client.get(ASSETS_ENDPOINT + assets[0]["data"])
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")
assert res.status_code == 200 assert res.status_code == 200
assert len(res.json) == 1 assert len(res.json) == 1
assert res.json[0] == {"data": assets[0]["data"]}