mirror of
https://github.com/planetmint/planetmint.git
synced 2025-11-25 06:55:45 +00:00
replaced metadata search with cid lookup
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
parent
9e5b7ac62d
commit
7ad4151984
@ -14,10 +14,10 @@ class MetaData:
|
|||||||
metadata: Optional[str] = None
|
metadata: Optional[str] = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_dict(meta_data_tuple: dict) -> MetaData | None:
|
def from_dict(meta_data: dict) -> MetaData | None:
|
||||||
if meta_data_tuple is None:
|
if meta_data is None:
|
||||||
return None
|
return None
|
||||||
return MetaData(meta_data_tuple["meta_data"])
|
return MetaData(meta_data)
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -96,6 +96,12 @@ def get_transactions_by_asset(connection, asset):
|
|||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def get_transactions_by_metadata(connection, metadata: str, limit: int = 1000) -> list[DbTransaction]:
|
||||||
|
""" Get a transaction by its metadata cid."""
|
||||||
|
|
||||||
|
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.
|
||||||
|
|||||||
@ -48,6 +48,11 @@ function init()
|
|||||||
{ field = 'assets[*].data', type = 'string', is_nullable = true }
|
{ field = 'assets[*].data', type = 'string', is_nullable = true }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
transactions:create_index('transactions_by_metadata_cid', {
|
||||||
|
if_not_exists = true,
|
||||||
|
unique = false,
|
||||||
|
parts = {{ field = 'metadata', type = 'string' }}
|
||||||
|
})
|
||||||
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 = {
|
||||||
@ -63,6 +68,21 @@ function init()
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
-- Governance
|
||||||
|
governance = box.schema.create_space('governance', { if_not_exists = true })
|
||||||
|
governance:format({
|
||||||
|
{ name = 'id', type = 'string' },
|
||||||
|
{ name = 'operation', type = 'string' },
|
||||||
|
{ name = 'version', type = 'string' },
|
||||||
|
{ name = 'metadata', type = 'string', is_nullable = true },
|
||||||
|
{ name = 'assets', type = 'array' },
|
||||||
|
{ name = 'inputs', type = 'array' },
|
||||||
|
{ name = 'scripts', type = 'map', is_nullable = true }
|
||||||
|
})
|
||||||
|
governance:create_index('id', {
|
||||||
|
if_not_exists = true,
|
||||||
|
parts = {{ field = 'id', type = 'string' }}
|
||||||
|
})
|
||||||
|
|
||||||
-- Outputs
|
-- Outputs
|
||||||
outputs = box.schema.create_space('outputs', { if_not_exists = true })
|
outputs = box.schema.create_space('outputs', { if_not_exists = true })
|
||||||
|
|||||||
@ -56,11 +56,21 @@ def get_transaction(connection, tx_id: str) -> DbTransaction:
|
|||||||
|
|
||||||
@register_query(TarantoolDBConnection)
|
@register_query(TarantoolDBConnection)
|
||||||
def get_transactions_by_asset(connection, asset: str, limit: int = 1000) -> list[DbTransaction]:
|
def get_transactions_by_asset(connection, asset: str, limit: int = 1000) -> list[DbTransaction]:
|
||||||
txs = connection.run(connection.space(TARANT_TABLE_TRANSACTION).select(asset, limit=limit, index="transactions_by_asset_cid"))
|
txs = connection.run(
|
||||||
|
connection.space(TARANT_TABLE_TRANSACTION).select(asset, limit=limit, index="transactions_by_asset_cid")
|
||||||
|
)
|
||||||
tx_ids = [tx[0] for tx in txs]
|
tx_ids = [tx[0] for tx in txs]
|
||||||
return get_complete_transactions_by_ids(connection, tx_ids)
|
return get_complete_transactions_by_ids(connection, tx_ids)
|
||||||
|
|
||||||
|
|
||||||
|
@register_query(TarantoolDBConnection)
|
||||||
|
def get_transactions_by_metadata(connection, metadata: str, limit: int = 1000) -> list[DbTransaction]:
|
||||||
|
txs = connection.run(
|
||||||
|
connection.space(TARANT_TABLE_TRANSACTION).select(metadata, limit=limit, index="transactions_by_metadata_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
|
||||||
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((
|
connection.run(connection.space(TARANT_TABLE_OUTPUT).insert((
|
||||||
|
|||||||
@ -470,6 +470,10 @@ class Planetmint(object):
|
|||||||
"""
|
"""
|
||||||
return backend.query.get_metadata(self.connection, txn_ids)
|
return backend.query.get_metadata(self.connection, txn_ids)
|
||||||
|
|
||||||
|
def get_metadata_by_cid(self, metadata_cid, **kwargs) -> list[str]:
|
||||||
|
metadata_txs = backend.query.get_transactions_by_metadata(self.connection, metadata_cid, **kwargs)
|
||||||
|
return [tx.metadata.metadata for tx in metadata_txs]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fastquery(self):
|
def fastquery(self):
|
||||||
return fastquery.FastQuery(self.connection)
|
return fastquery.FastQuery(self.connection)
|
||||||
|
|||||||
@ -32,7 +32,7 @@ def r(*args, **kwargs):
|
|||||||
ROUTES_API_V1 = [
|
ROUTES_API_V1 = [
|
||||||
r("/", info.ApiV1Index),
|
r("/", info.ApiV1Index),
|
||||||
r("assets/<string:cid>", assets.AssetListApi),
|
r("assets/<string:cid>", assets.AssetListApi),
|
||||||
r("metadata/", metadata.MetadataApi),
|
r("metadata/<string:cid>", 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),
|
||||||
r("blocks/", blocks.BlockListApi),
|
r("blocks/", blocks.BlockListApi),
|
||||||
|
|||||||
@ -18,33 +18,28 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class MetadataApi(Resource):
|
class MetadataApi(Resource):
|
||||||
def get(self):
|
def get(self, cid):
|
||||||
"""API endpoint to perform a text search on transaction metadata.
|
"""API endpoint to perform a text search on transaction metadata.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
search (str): Text search string to query the text index
|
|
||||||
limit (int, optional): Limit the number of returned documents.
|
limit (int, optional): Limit the number of returned documents.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
A list of metadata that match the query.
|
A list of metadata that match the query.
|
||||||
"""
|
"""
|
||||||
parser = reqparse.RequestParser()
|
parser = reqparse.RequestParser()
|
||||||
parser.add_argument("search", type=str, required=True)
|
|
||||||
parser.add_argument("limit", type=int)
|
parser.add_argument("limit", type=int)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if not args["search"]:
|
|
||||||
return make_error(400, "text_search cannot be empty")
|
|
||||||
if not args["limit"]:
|
if not args["limit"]:
|
||||||
del args["limit"]
|
del args["limit"]
|
||||||
|
|
||||||
pool = current_app.config["bigchain_pool"]
|
pool = current_app.config["bigchain_pool"]
|
||||||
|
|
||||||
with pool() as planet:
|
with pool() as planet:
|
||||||
args["table"] = "meta_data"
|
metadata = planet.get_metadata_by_cid(cid, **args)
|
||||||
metadata = planet.text_search(**args)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return list(metadata)
|
return metadata
|
||||||
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))
|
||||||
|
|||||||
@ -11,22 +11,11 @@ from ipld import marshal, multihash
|
|||||||
METADATA_ENDPOINT = "/api/v1/metadata/"
|
METADATA_ENDPOINT = "/api/v1/metadata/"
|
||||||
|
|
||||||
|
|
||||||
def test_get_metadata_with_empty_text_search(client):
|
|
||||||
res = client.get(METADATA_ENDPOINT + "?search=")
|
|
||||||
assert res.json == {"status": 400, "message": "text_search cannot be empty"}
|
|
||||||
assert res.status_code == 400
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_metadata_with_missing_text_search(client):
|
|
||||||
res = client.get(METADATA_ENDPOINT)
|
|
||||||
assert res.status_code == 400
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_get_metadata_tendermint(client, b, alice):
|
def test_get_metadata_tendermint(client, b, alice):
|
||||||
assets = [{"data": multihash(marshal({"msg": "abc"}))}]
|
assets = [{"data": multihash(marshal({"msg": "abc"}))}]
|
||||||
# test returns empty list when no assets are found
|
# test returns empty list when no assets are found
|
||||||
res = client.get(METADATA_ENDPOINT + "?search=" + assets[0]["data"])
|
res = client.get(METADATA_ENDPOINT + assets[0]["data"])
|
||||||
assert res.json == []
|
assert res.json == []
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
|
|
||||||
@ -40,10 +29,10 @@ def test_get_metadata_tendermint(client, b, alice):
|
|||||||
b.store_bulk_transactions([tx])
|
b.store_bulk_transactions([tx])
|
||||||
|
|
||||||
# test that metadata is returned
|
# test that metadata is returned
|
||||||
res = client.get(METADATA_ENDPOINT + "?search=" + metadata)
|
res = client.get(METADATA_ENDPOINT + metadata)
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
assert len(res.json) == 1
|
assert len(res.json) == 1
|
||||||
assert res.json[0] == {"meta_data": metadata, "id": tx.id}
|
assert res.json[0] == metadata
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
@ -51,25 +40,24 @@ def test_get_metadata_limit_tendermint(client, b, alice):
|
|||||||
|
|
||||||
# create two assets
|
# create two assets
|
||||||
assets1 = [{"data": multihash(marshal({"msg": "abc 1"}))}]
|
assets1 = [{"data": multihash(marshal({"msg": "abc 1"}))}]
|
||||||
meta1 = multihash(marshal({"key": "meta 1"}))
|
meta = multihash(marshal({"key": "meta 1"}))
|
||||||
tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta1, assets=assets1).sign(
|
tx1 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta, assets=assets1).sign(
|
||||||
[alice.private_key]
|
[alice.private_key]
|
||||||
)
|
)
|
||||||
b.store_bulk_transactions([tx1])
|
b.store_bulk_transactions([tx1])
|
||||||
|
|
||||||
assets2 = [{"data": multihash(marshal({"msg": "abc 2"}))}]
|
assets2 = [{"data": multihash(marshal({"msg": "abc 2"}))}]
|
||||||
meta2 = multihash(marshal({"key": "meta 2"}))
|
tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta, assets=assets2).sign(
|
||||||
tx2 = Create.generate([alice.public_key], [([alice.public_key], 1)], metadata=meta2, assets=assets2).sign(
|
|
||||||
[alice.private_key]
|
[alice.private_key]
|
||||||
)
|
)
|
||||||
b.store_bulk_transactions([tx2])
|
b.store_bulk_transactions([tx2])
|
||||||
|
|
||||||
# test that both assets are returned without limit
|
# test that both assets are returned without limit
|
||||||
res = client.get(METADATA_ENDPOINT + "?search=" + meta1)
|
res = client.get(METADATA_ENDPOINT + meta)
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
assert len(res.json) == 1
|
assert len(res.json) == 2
|
||||||
|
|
||||||
# test that only one asset is returned when using limit=1
|
# test that only one asset is returned when using limit=1
|
||||||
res = client.get(METADATA_ENDPOINT + "?search=" + meta2 + "&limit=1")
|
res = client.get(METADATA_ENDPOINT + meta + "?limit=1")
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
assert len(res.json) == 1
|
assert len(res.json) == 1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user