Change metadata model, fix tests and update docs

This commit is contained in:
kansi 2017-11-14 00:13:06 +05:30
parent 832ecb5e63
commit 4eca26782c
6 changed files with 140 additions and 34 deletions

View File

@ -366,10 +366,7 @@ def get_new_blocks_feed(conn, start_block_id):
@register_query(MongoDBConnection)
def text_search(conn, search, *, language='english', case_sensitive=False,
diacritic_sensitive=False, text_score=False, limit=0, table=None):
if table is None:
table = 'assets'
diacritic_sensitive=False, text_score=False, limit=0, table='assets'):
cursor = conn.run(
conn.collection(table)
.find({'$text': {

View File

@ -384,8 +384,8 @@ class Bigchain(object):
for transaction in transactions:
# ignore transactions in invalid blocks
# FIXME: Isn't there a faster solution than doing I/O again?
_, status = self.get_transaction(transaction['id'],
include_status=True)
txn, status = self.get_transaction(transaction['id'],
include_status=True)
if status == self.TX_VALID:
num_valid_transactions += 1
# `txid` can only have been spent in at most on valid block.
@ -395,13 +395,7 @@ class Bigchain(object):
' with the chain'.format(txid))
# if its not and invalid transaction
if status is not None:
if 'metadata' not in transaction:
metadata = list(self.get_metadata([transaction['id']]))
metadata = metadata[0] if metadata else None
if metadata:
metadata.pop('id', None)
transaction.update({'metadata': metadata})
transaction.update({'metadata': txn.metadata})
non_invalid_transactions.append(transaction)
if non_invalid_transactions:
@ -672,7 +666,7 @@ class Bigchain(object):
"""
return backend.query.write_metadata(self.connection, metadata)
def text_search(self, search, *, limit=0, table=None):
def text_search(self, search, *, limit=0, table='assets'):
"""
Return an iterator of assets that match the text search
@ -683,9 +677,6 @@ class Bigchain(object):
Returns:
iter: An iterator of assets that match the text search.
"""
if table is None:
table = 'assets'
objects = backend.query.text_search(self.connection, search, limit=limit,
table=table)

View File

@ -5,8 +5,7 @@ from bigchaindb.common.exceptions import (InvalidHash, InvalidSignature,
DoubleSpend, InputDoesNotExist,
TransactionNotInValidBlock,
AssetIdMismatch, AmountError,
SybilError, ValidationError,
DuplicateTransaction)
SybilError, DuplicateTransaction)
from bigchaindb.common.transaction import Transaction
from bigchaindb.common.utils import (gen_timestamp, serialize,
validate_txn_obj, validate_key)
@ -119,7 +118,7 @@ class Transaction(Transaction):
if 'metadata' not in tx_dict:
metadata = metadata[0] if metadata else None
if metadata:
metadata.pop('id', None)
metadata = metadata.get('metadata')
tx_dict.update({'metadata': metadata})
@ -406,11 +405,10 @@ class Block(object):
metadatas = []
for transaction in block_dict['block']['transactions']:
metadata = transaction.pop('metadata')
if isinstance(metadata, dict):
metadata.update({'id': transaction['id']})
metadatas.append(metadata)
elif metadata:
raise ValidationError('Invalid value for metadata')
if metadata:
metadata_new = {'id': transaction['id'],
'metadata': metadata}
metadatas.append(metadata_new)
return (metadatas, block_dict)
@ -460,16 +458,11 @@ class Block(object):
dict: The dict of the reconstructed block.
"""
# create a dict with {'<txid>': metadata}
metadatal = {m.pop('id'): m for m in metadatal}
metadatal = {m.pop('id'): m.pop('metadata') for m in metadatal}
# add the metadata to their corresponding transactions
for transaction in block_dict['block']['transactions']:
if 'metadata' not in transaction:
metadata = metadatal.get(transaction['id'])
if metadata:
metadata.pop('id', None)
transaction.update({'metadata': metadata})
else:
transaction.update({'metadata': None})
metadata = metadatal.get(transaction['id'], None)
transaction.update({'metadata': metadata})
return block_dict
@staticmethod

View File

@ -452,6 +452,118 @@ Assets
text search.
Transaction Metadata
--------------------------------
.. http:get:: /api/v1/metadata
Return all the metadata that match a given text search.
:query string text search: Text search string to query.
:query int limit: (Optional) Limit the number of returned metadata objects. Defaults
to ``0`` meaning return all matching objects.
.. note::
Currently this enpoint is only supported if the server is running
MongoDB as the backend.
.. http:get:: /api/v1/metadata/?search={text_search}
Return all metadata that match a given text search. The ``id`` of the metadata
is the same ``id`` of the transaction where it was defined.
If no metadata match the text search it returns an empty list.
If the text string is empty or the server does not support text search,
a ``400`` is returned.
The results are sorted by text score.
For more information about the behavior of text search see `MongoDB text
search behavior <https://docs.mongodb.com/manual/reference/operator/query/text/#behavior>`_
**Example request**:
.. sourcecode:: http
GET /api/v1/metadata/?search=bigchaindb HTTP/1.1
Host: example.com
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-type: application/json
[
{
"metadata": {"metakey1": "Hello BigchainDB 1!"},
"id": "51ce82a14ca274d43e4992bbce41f6fdeb755f846e48e710a3bbb3b0cf8e4204"
},
{
"metadata": {"metakey2": "Hello BigchainDB 2!"},
"id": "b4e9005fa494d20e503d916fa87b74fe61c079afccd6e084260674159795ee31"
},
{
"metadata": {"metakey3": "Hello BigchainDB 3!"},
"id": "fa6bcb6a8fdea3dc2a860fcdc0e0c63c9cf5b25da8b02a4db4fb6a2d36d27791"
}
]
:resheader Content-Type: ``application/json``
:statuscode 200: The query was executed successfully.
:statuscode 400: The query was not executed successfully. Returned if the
text string is empty or the server does not support
text search.
.. http:get:: /api/v1/metadata/?search={text_search}&limit={n_documents}
Return at most ``n`` metadata objects that match a given text search.
If no metadata match the text search it returns an empty list.
If the text string is empty or the server does not support text search,
a ``400`` is returned.
The results are sorted by text score.
For more information about the behavior of text search see `MongoDB text
search behavior <https://docs.mongodb.com/manual/reference/operator/query/text/#behavior>`_
**Example request**:
.. sourcecode:: http
GET /api/v1/metadata/?search=bigchaindb&limit=2 HTTP/1.1
Host: example.com
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Content-type: application/json
[
{
"metadata": {"msg": "Hello BigchainDB 1!"},
"id": "51ce82a14ca274d43e4992bbce41f6fdeb755f846e48e710a3bbb3b0cf8e4204"
},
{
"metadata": {"msg": "Hello BigchainDB 2!"},
"id": "b4e9005fa494d20e503d916fa87b74fe61c079afccd6e084260674159795ee31"
},
]
:resheader Content-Type: ``application/json``
:statuscode 200: The query was executed successfully.
:statuscode 400: The query was not executed successfully. Returned if the
text string is empty or the server does not support
text search.
Advanced Usage
--------------------------------

View File

@ -29,6 +29,16 @@ def decouple_assets(b, block):
return block_dict
def decouple_metadata(b, block, block_dict):
# the block comming from the database does not contain the metadata
# so we need to pass the block without the metadata and store the metadata
# so that the voting pipeline can reconstruct it
metadata, block_dict = block.decouple_metadata(block_dict)
if metadata:
b.write_metadata(metadata)
return block_dict
DUMMY_SHA3 = '0123456789abcdef' * 4
@ -89,6 +99,7 @@ def test_vote_validate_block(b):
tx = dummy_tx(b)
block = b.create_block([tx])
block_dict = decouple_assets(b, block)
block_dict = decouple_metadata(b, block, block_dict)
vote_obj = vote.Vote()
validation = vote_obj.validate_block(block_dict)
@ -230,6 +241,7 @@ def test_valid_block_voting_multiprocessing(b, genesis_block, monkeypatch):
block = dummy_block(b)
block_dict = decouple_assets(b, block)
block_dict = decouple_metadata(b, block, block_dict)
inpipe.put(block_dict)
vote_pipeline.start()
@ -268,6 +280,7 @@ def test_valid_block_voting_with_create_transaction(b,
monkeypatch.setattr('time.time', lambda: 1111111111)
block = b.create_block([tx])
block_dict = decouple_assets(b, block)
block_dict = decouple_metadata(b, block, block_dict)
inpipe = Pipe()
outpipe = Pipe()

View File

@ -43,7 +43,7 @@ def test_get_metadata(client, b):
assert res.status_code == 200
assert len(res.json) == 1
assert res.json[0] == {
'key': 'my_meta',
'metadata': {'key': 'my_meta'},
'id': tx.id
}
else: