Transcation API extension: last_tx parameter (#2667)

* added last_tx switch to the TX get query to only get the latest TX for a given asset.
* extended test case to contain last_tx field
* Add last_tx option in query module
* Fix natural descending cursor sort argument
This commit is contained in:
Jürgen Eckel 2019-11-06 23:23:14 +01:00 committed by GitHub
parent ecd6e9cc46
commit b54c31539f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 39 additions and 34 deletions

View File

@ -120,29 +120,19 @@ def store_block(conn, block):
@register_query(LocalMongoDBConnection) @register_query(LocalMongoDBConnection)
def get_txids_filtered(conn, asset_id, operation=None): def get_txids_filtered(conn, asset_id, operation=None, last_tx=None):
match_create = {
'operation': 'CREATE',
'id': asset_id
}
match_transfer = {
'operation': 'TRANSFER',
'asset.id': asset_id
}
if operation == Transaction.CREATE: match = {
match = match_create Transaction.CREATE: {'operation': 'CREATE', 'id': asset_id},
elif operation == Transaction.TRANSFER: Transaction.TRANSFER: {'operation': 'TRANSFER', 'asset.id': asset_id},
match = match_transfer None: {'$or': [{'asset.id': asset_id}, {'id': asset_id}]},
else: }[operation]
match = {'$or': [match_create, match_transfer]}
cursor = conn.run(conn.collection('transactions').find(match))
if last_tx:
cursor = cursor.sort([('$natural', DESCENDING)]).limit(1)
pipeline = [
{'$match': match}
]
cursor = conn.run(
conn.collection('transactions')
.aggregate(pipeline))
return (elem['id'] for elem in cursor) return (elem['id'] for elem in cursor)

View File

@ -261,11 +261,11 @@ class BigchainDB(object):
def get_transactions(self, txn_ids): def get_transactions(self, txn_ids):
return backend.query.get_transactions(self.connection, txn_ids) return backend.query.get_transactions(self.connection, txn_ids)
def get_transactions_filtered(self, asset_id, operation=None): def get_transactions_filtered(self, asset_id, operation=None, last_tx=None):
"""Get a list of transactions filtered on some criteria """Get a list of transactions filtered on some criteria
""" """
txids = backend.query.get_txids_filtered(self.connection, asset_id, txids = backend.query.get_txids_filtered(self.connection, asset_id,
operation) operation, last_tx)
for txid in txids: for txid in txids:
yield self.get_transaction(txid) yield self.get_transaction(txid)

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0) # SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0 # Code is Apache-2.0 and docs are CC-BY-4.0
__version__ = '2.0.0' __version__ = '2.1.0'
__short_version__ = '2.0' __short_version__ = '2.1'
# Supported Tendermint versions # Supported Tendermint versions
__tm_supported_versions__ = ["0.31.5"] __tm_supported_versions__ = ["0.31.5"]

View File

@ -48,8 +48,9 @@ class TransactionListApi(Resource):
parser.add_argument('operation', type=parameters.valid_operation) parser.add_argument('operation', type=parameters.valid_operation)
parser.add_argument('asset_id', type=parameters.valid_txid, parser.add_argument('asset_id', type=parameters.valid_txid,
required=True) required=True)
parser.add_argument('last_tx', type=parameters.valid_bool,
required=False)
args = parser.parse_args() args = parser.parse_args()
with current_app.config['bigchain_pool']() as bigchain: with current_app.config['bigchain_pool']() as bigchain:
txs = bigchain.get_transactions_filtered(**args) txs = bigchain.get_transactions_filtered(**args)

View File

@ -91,7 +91,7 @@ Transactions
Requests to the ``/api/v1/transactions`` endpoint Requests to the ``/api/v1/transactions`` endpoint
without any query parameters will get a response status code ``400 Bad Request``. without any query parameters will get a response status code ``400 Bad Request``.
.. http:get:: /api/v1/transactions?asset_id={asset_id}&operation={CREATE|TRANSFER} .. http:get:: /api/v1/transactions?asset_id={asset_id}&operation={CREATE|TRANSFER}&last_tx={true|false}
Get a list of transactions that use an asset with the ID ``asset_id``. Get a list of transactions that use an asset with the ID ``asset_id``.
@ -106,12 +106,18 @@ Transactions
If ``operation`` is not included, then *every* transaction involving If ``operation`` is not included, then *every* transaction involving
the asset with ID ``asset_id`` will be returned. the asset with ID ``asset_id`` will be returned.
if ``last_tx`` is set to ``true``, only the last transaction is returned
instead of all transactions with the given ``asset_id``.
This endpoint returns transactions only if they are in committed blocks. This endpoint returns transactions only if they are in committed blocks.
:query string operation: (Optional) ``CREATE`` or ``TRANSFER``. :query string operation: (Optional) ``CREATE`` or ``TRANSFER``.
:query string asset_id: asset ID. :query string asset_id: asset ID.
:query string last_tx: (Optional) ``true`` or ``false``.
**Example request**: **Example request**:
.. literalinclude:: http-samples/get-tx-by-asset-request.http .. literalinclude:: http-samples/get-tx-by-asset-request.http
@ -141,7 +147,7 @@ Transactions
Otherwise, the node will send the transaction to Tendermint (in the same node) using the Otherwise, the node will send the transaction to Tendermint (in the same node) using the
`Tendermint broadcast API `Tendermint broadcast API
<https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_. <https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_.
The meaning of the ``mode`` query parameter is inherited from the mode parameter in The meaning of the ``mode`` query parameter is inherited from the mode parameter in
`Tendermint's broadcast API `Tendermint's broadcast API
<https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_. <https://tendermint.com/docs/tendermint-core/using-tendermint.html#broadcast-api>`_.
@ -191,7 +197,7 @@ Transactions
:resheader Content-Type: ``application/json`` :resheader Content-Type: ``application/json``
:statuscode 202: The meaning of this response depends on the value :statuscode 202: The meaning of this response depends on the value
of the ``mode`` parameter. See above. of the ``mode`` parameter. See above.
:statuscode 400: The posted transaction was invalid. :statuscode 400: The posted transaction was invalid.
@ -347,14 +353,14 @@ Assets
.. http:get:: /api/v1/assets/?search={search} .. http:get:: /api/v1/assets/?search={search}
Return all assets that match a given text search. Return all assets that match a given text search.
.. note:: .. note::
The ``id`` of the asset The ``id`` of the asset
is the same ``id`` of the CREATE transaction that created the asset. is the same ``id`` of the CREATE transaction that created the asset.
.. note:: .. note::
You can use ``assets/?search`` or ``assets?search``. You can use ``assets/?search`` or ``assets?search``.
If no assets match the text search it returns an empty list. If no assets match the text search it returns an empty list.
@ -471,14 +477,14 @@ Transaction Metadata
.. http:get:: /api/v1/metadata/?search={search} .. http:get:: /api/v1/metadata/?search={search}
Return all metadata objects that match a given text search. Return all metadata objects that match a given text search.
.. note:: .. note::
The ``id`` of the metadata The ``id`` of the metadata
is the same ``id`` of the transaction where it was defined. is the same ``id`` of the transaction where it was defined.
.. note:: .. note::
You can use ``metadata/?search`` or ``metadata?search``. You can use ``metadata/?search`` or ``metadata?search``.
If no metadata objects match the text search it returns an empty list. If no metadata objects match the text search it returns an empty list.

View File

@ -382,13 +382,21 @@ def test_transactions_get_list_good(client):
url = TX_ENDPOINT + '?asset_id=' + asset_id url = TX_ENDPOINT + '?asset_id=' + asset_id
assert client.get(url).json == [ assert client.get(url).json == [
['asset_id', asset_id], ['asset_id', asset_id],
['last_tx', None],
['operation', None] ['operation', None]
] ]
url = TX_ENDPOINT + '?asset_id=' + asset_id + '&operation=CREATE' url = TX_ENDPOINT + '?asset_id=' + asset_id + '&operation=CREATE'
assert client.get(url).json == [ assert client.get(url).json == [
['asset_id', asset_id], ['asset_id', asset_id],
['last_tx', None],
['operation', 'CREATE'] ['operation', 'CREATE']
] ]
url = TX_ENDPOINT + '?asset_id=' + asset_id + '&last_tx=true'
assert client.get(url).json == [
['asset_id', asset_id],
['last_tx', True],
['operation', None]
]
def test_transactions_get_list_bad(client): def test_transactions_get_list_bad(client):