def embedded_document(reference, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # support late versioning if reference[config.VERSION] == 1: # there is a chance this document hasn't been saved # since versioning was turned on embedded_doc = missing_version_field(data_relation, reference) if embedded_doc is None: # this document has been saved since the data_relation was # made - we basically do not have the copy of the document # that existed when the data relation was made, but we'll # try the next best thing - the first version reference[config.VERSION] = 1 embedded_doc = get_data_version_relation_document( data_relation, reference) latest_embedded_doc = embedded_doc else: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name )) # build the response document build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: subresource = data_relation['resource'] embedded_doc = app.data.find_one(subresource, None, **{config.ID_FIELD: reference}) if embedded_doc: resolve_media_files(embedded_doc, subresource) return embedded_doc
def embedded_document(reference, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # support late versioning if reference[config.VERSION] == 1: # there is a chance this document hasn't been saved # since versioning was turned on embedded_doc = missing_version_field(data_relation, reference) if embedded_doc is None: # this document has been saved since the data_relation was # made - we basically do not have the copy of the document # that existed when the data relation was made, but we'll # try the next best thing - the first version reference[config.VERSION] = 1 embedded_doc = get_data_version_relation_document( data_relation, reference) latest_embedded_doc = embedded_doc else: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name)) # build the response document build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: subresource = data_relation['resource'] embedded_doc = app.data.find_one(subresource, None, **{config.ID_FIELD: reference}) if embedded_doc: resolve_media_files(embedded_doc, subresource) return embedded_doc
def embedded_document(reference, data_relation, field_name, child_embed): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document(data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad # TODO: we should notify the developers with a log. abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name)) build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: # if reference is DBRef take the referenced collection as subresource subresource = reference.collection if isinstance(reference, DBRef) \ else data_relation['resource'] id_field = config.DOMAIN[subresource]['id_field'] # build a fake request to carry our embedded fields list req = ParsedRequest() req.embedded = json.dumps({key: 1 for key in child_embed}) embedded_doc = app.data.find_one( subresource, req, **{ id_field: reference.id if isinstance(reference, DBRef) else reference }) if embedded_doc: resolve_media_files(embedded_doc, subresource) return embedded_doc
def embedded_document(reference, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad # TODO: we should notify the developers with a log. abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name )) build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: # if reference is DBRef take the referenced collection as subresource subresource = reference.collection if isinstance(reference, DBRef) \ else data_relation['resource'] id_field = config.DOMAIN[subresource]['id_field'] embedded_doc = app.data.find_one(subresource, None, **{id_field: reference.id if isinstance(reference, DBRef) else reference}) if embedded_doc: resolve_media_files(embedded_doc, subresource) return embedded_doc
def embedded_document(reference, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document(data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad # TODO: we should notify the developers with a log. abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name)) build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: subresource = data_relation['resource'] id_field = config.DOMAIN[subresource]['id_field'] embedded_doc = app.data.find_one(subresource, None, **{id_field: reference}) if embedded_doc: resolve_media_files(embedded_doc, subresource) return embedded_doc
def _validate_data_relation(self, data_relation, field, value): """ {'type': 'dict', 'schema': { 'resource': {'type': 'string', 'required': True}, 'field': {'type': 'string', 'required': True}, 'embeddable': {'type': 'boolean', 'default': False}, 'version': {'type': 'boolean', 'default': False} }} """ if 'version' in data_relation and data_relation['version'] is True: value_field = data_relation['field'] version_field = app.config['VERSION'] # check value format if isinstance(value, dict) and value_field in value \ and version_field in value: resource_def = config.DOMAIN[data_relation['resource']] if resource_def['versioning'] is False: self._error( field, "can't save a version with" " data_relation if '%s' isn't versioned" % data_relation['resource']) else: search = get_data_version_relation_document( data_relation, value) if not search: self._error( field, "value '%s' must exist in resource" " '%s', field '%s' at version '%s'." % (value[value_field], data_relation['resource'], data_relation['field'], value[version_field])) else: self._error( field, "versioned data_relation must be a dict" " with fields '%s' and '%s'" % (value_field, version_field)) else: if not isinstance(value, list): value = [value] data_resource = data_relation['resource'] for item in value: query = { data_relation['field']: item.id if isinstance(item, DBRef) else item } if not app.data.find_one(data_resource, None, **query): self._error( field, "value '%s' must exist in resource" " '%s', field '%s'." % (item.id if isinstance(item, DBRef) else item, data_resource, data_relation['field']))
def _validate_data_relation(self, data_relation, field, value): """ {'type': 'dict', 'schema': { 'resource': {'type': 'string', 'required': True}, 'field': {'type': 'string', 'required': True}, 'embeddable': {'type': 'boolean', 'default': False}, 'version': {'type': 'boolean', 'default': False} }} """ if 'version' in data_relation and data_relation['version'] is True: value_field = data_relation['field'] version_field = app.config['VERSION'] # check value format if isinstance(value, dict) and value_field in value \ and version_field in value: resource_def = config.DOMAIN[data_relation['resource']] if resource_def['versioning'] is False: self._error( field, "can't save a version with" " data_relation if '%s' isn't versioned" % data_relation['resource']) else: search = get_data_version_relation_document( data_relation, value) if not search: self._error( field, "value '%s' must exist in resource" " '%s', field '%s' at version '%s'." % ( value[value_field], data_relation['resource'], data_relation['field'], value[version_field])) else: self._error( field, "versioned data_relation must be a dict" " with fields '%s' and '%s'" % (value_field, version_field)) else: if not isinstance(value, list): value = [value] data_resource = data_relation['resource'] for item in value: query = {data_relation['field']: item.id if isinstance(item, DBRef) else item} if not app.data.find_one(data_resource, None, **query): self._error( field, "value '%s' must exist in resource" " '%s', field '%s'." % (item.id if isinstance(item, DBRef) else item, data_resource, data_relation['field']))
def _validate_data_relation(self, data_relation, field, value): if 'version' in data_relation and data_relation['version'] is True: value_field = data_relation['field'] version_field = app.config['VERSION'] # check value format if isinstance(value, dict) and value_field in value and \ version_field in value: resource_def = config.DOMAIN[data_relation['resource']] if resource_def['versioning'] is False: self._error(field, ("can't save a version with " "data_relation if '%s' isn't " "versioned") % data_relation['resource']) else: # support late versioning if value[version_field] == 0: # there is a chance this document hasn't been saved # since versioning was turned on search = missing_version_field(data_relation, value) else: search = get_data_version_relation_document( data_relation, value) if not search: self._error(field, ("value '%s' must exist in resource" " '%s', field '%s' at version " "'%s'.") % ( value[value_field], data_relation['resource'], data_relation['field'], value[version_field])) else: self._error(field, ("versioned data_relation must be a dict " "with fields '%s' and '%s'") % (value_field, version_field)) else: query = {data_relation['field']: value} if not app.data.find_one(data_relation['resource'], None, **query): self._error(field, ("value '%s' must exist in resource '%s', " "field '%s'") % (value, data_relation['resource'], data_relation['field']))
def _validate_data_relation(self, data_relation, field, value): if 'version' in data_relation and data_relation['version'] is True: value_field = data_relation['field'] version_field = app.config['VERSION'] # check value format if isinstance(value, dict) and value_field in value and \ version_field in value: resource_def = config.DOMAIN[data_relation['resource']] if resource_def['versioning'] is False: self._error(field, ("can't save a version with " "data_relation if '%s' isn't " "versioned") % data_relation['resource']) else: # support late versioning if value[version_field] == 0: # there is a chance this document hasn't been saved # since versioning was turned on search = missing_version_field(data_relation, value) else: search = get_data_version_relation_document( data_relation, value) if not search: self._error(field, ("value '%s' must exist in resource" " '%s', field '%s' at version " "'%s'.") % ( value[value_field], data_relation['resource'], data_relation['field'], value[version_field])) else: self._error(field, ("versioned data_relation must be a dict " "with fields '%s' and '%s'") % (value_field, version_field)) else: query = {data_relation['field']: value} if not app.data.find_one(data_relation['resource'], None, **query): self._error(field, ("value '%s' must exist in resource '%s', " "field '%s'.") % (value, data_relation['resource'], data_relation['field']))
def _validate_data_relation(self, data_relation, field, value): """ Enables validation for `data_relation` field attribute. Makes sure 'value' of 'field' adheres to the referential integrity rule specified by 'data_relation'. :param data_relation: a dict following keys: 'collection': foreign collection name 'field': foreign field name 'version': True if this relation points to a specific version 'type': the type for the reference field if 'version': True :param field: field name. :param value: field value. .. versionchanged:: 0.4 Support for document versioning. .. versionchanged:: 0.3 Support for new 'self._error' signature introduced with Cerberus v0.5. .. versionchanged:: 0.1.1 'collection' key renamed to 'resource' (data_relation) .. versionadded: 0.0.5 """ if 'version' in data_relation and data_relation['version'] is True: value_field = data_relation['field'] version_field = app.config['VERSION'] # check value format if isinstance(value, dict) and value_field in value \ and version_field in value: resource_def = config.DOMAIN[data_relation['resource']] if resource_def['versioning'] is False: self._error( field, "can't save a version with" " data_relation if '%s' isn't versioned" % data_relation['resource']) else: search = None # support late versioning if value[version_field] == 1: # there is a chance this document hasn't been saved # since versioning was turned on search = missing_version_field(data_relation, value) if not search: search = get_data_version_relation_document( data_relation, value) if not search: self._error( field, "value '%s' must exist in resource" " '%s', field '%s' at version '%s'." % ( value[value_field], data_relation['resource'], data_relation['field'], value[version_field])) else: self._error( field, "versioned data_relation must be a dict" " with fields '%s' and '%s'" % (value_field, version_field)) else: query = {data_relation['field']: value} if not app.data.find_one(data_relation['resource'], None, **query): self._error( field, "value '%s' must exist in resource '%s', field '%s'." % (value, data_relation['resource'], data_relation['field']))
def embedded_document(references, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ embedded_docs = [] output_is_list = True if not isinstance(references, list): output_is_list = False references = [references] # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # For the version flow, I keep the as-is logic (flow is too complex to make it bulk) for reference in references: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad # TODO: we should notify the developers with a log. abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name)) build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) embedded_docs.append(embedded_doc) else: id_value_to_sort, list_of_id_field_name, subresources_query = generate_query_and_sorting_criteria( data_relation, references) for subresource in subresources_query: list_embedded_doc = list( app.data.find(subresource, None, subresources_query[subresource])) if not list_embedded_doc: embedded_docs.extend( [None] * len(subresources_query[subresource]["$or"])) else: for embedded_doc in list_embedded_doc: resolve_media_files(embedded_doc, subresource) embedded_docs.extend(list_embedded_doc) # After having retrieved my data, I have to be sure that the sorting of the # list is the same in input as in output (this is to support embedding of # sub-documents - only in case the storage is not done via DBref) if embedded_docs: embedded_docs = sort_db_response(embedded_docs, id_value_to_sort, list_of_id_field_name) if output_is_list: return embedded_docs elif embedded_docs: return embedded_docs[0] else: return None
def resolve_embedded_documents(document, resource, embedded_fields): """ Loops through the documents, adding embedded representations of any fields that are (1) defined eligible for embedding in the DOMAIN and (2) requested to be embedded in the current `req`. Currently we only support a single layer of embedding, i.e. /invoices/?embedded={"user":1} *NOT* /invoices/?embedded={"user.friends":1} :param document: the document to embed other documents into. :param resource: the resource name. :param embedded_fields: the list of fields we are allowed to embed. .. versionchagend:: 0.4 Moved parsing of embedded fields to _resolve_embedded_fields. Support for document versioning. .. versionchagend:: 0.2 Support for 'embedded_fields'. .. versonchanged:: 0.1.1 'collection' key has been renamed to 'resource' (data_relation). .. versionadded:: 0.1.0 """ schema = config.DOMAIN[resource]['schema'] for field in embedded_fields: data_relation = schema[field]['data_relation'] # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # support late versioning if document[field][config.VERSION] == 1: # there is a chance this document hasn't been saved # since versioning was turned on embedded_doc = missing_version_field( data_relation, document[field]) if embedded_doc is None: # this document has been saved since the data_relation was # made - we basically do not have the copy of the document # that existed when the data relation was made, but we'll # try the next best thing - the first version document[field][config.VERSION] = 1 embedded_doc = get_data_version_relation_document( data_relation, document[field]) latest_embedded_doc = embedded_doc else: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, document[field]) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, document[field], latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field )) # build the response document build_response_document( embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: embedded_doc = app.data.find_one( data_relation['resource'], None, **{config.ID_FIELD: document[field]} ) if embedded_doc: document[field] = embedded_doc
def embedded_document(references, data_relation, field_name): """ Returns a document to be embedded by reference using data_relation taking into account document versions :param reference: reference to the document to be embedded. :param data_relation: the relation schema definition. :param field_name: field name used in abort message only .. versionadded:: 0.5 """ embedded_docs = [] output_is_list = True if not isinstance(references, list): output_is_list = False references = [references] # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # For the version flow, I keep the as-is logic (flow is too complex to # make it bulk) for reference in references: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, reference) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, reference, latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad # TODO: we should notify the developers with a log. abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field_name )) build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) embedded_docs.append(embedded_doc) else: id_value_to_sort, list_of_id_field_name, subresources_query = \ generate_query_and_sorting_criteria(data_relation, references) for subresource in subresources_query: list_embedded_doc = list( app.data.find(subresource, None, subresources_query[subresource])) if not list_embedded_doc: embedded_docs.extend( [None] * len(subresources_query[subresource]["$or"])) else: for embedded_doc in list_embedded_doc: resolve_media_files(embedded_doc, subresource) embedded_docs.extend(list_embedded_doc) # After having retrieved my data, I have to be sure that the sorting of # the list is the same in input as in output (this is to support # embedding of sub-documents - only in case the storage is not done via # DBref) if embedded_docs: embedded_docs = sort_db_response(embedded_docs, id_value_to_sort, list_of_id_field_name) if output_is_list: return embedded_docs elif embedded_docs: return embedded_docs[0] else: return None
def resolve_embedded_documents(document, resource, embedded_fields): """ Loops through the documents, adding embedded representations of any fields that are (1) defined eligible for embedding in the DOMAIN and (2) requested to be embedded in the current `req`. Currently we only support a single layer of embedding, i.e. /invoices/?embedded={"user":1} *NOT* /invoices/?embedded={"user.friends":1} :param document: the document to embed other documents into. :param resource: the resource name. :param embedded_fields: the list of fields we are allowed to embed. .. versionchagend:: 0.4 Moved parsing of embedded fields to _resolve_embedded_fields. Support for document versioning. .. versionchagend:: 0.2 Support for 'embedded_fields'. .. versonchanged:: 0.1.1 'collection' key has been renamed to 'resource' (data_relation). .. versionadded:: 0.1.0 """ schema = config.DOMAIN[resource]['schema'] for field in embedded_fields: data_relation = schema[field]['data_relation'] # Retrieve and serialize the requested document if 'version' in data_relation and data_relation['version'] is True: # support late versioning if document[field][config.VERSION] == 1: # there is a chance this document hasn't been saved # since versioning was turned on embedded_doc = missing_version_field(data_relation, document[field]) if embedded_doc is None: # this document has been saved since the data_relation was # made - we basically do not have the copy of the document # that existed when the data relation was made, but we'll # try the next best thing - the first version document[field][config.VERSION] = 1 embedded_doc = get_data_version_relation_document( data_relation, document[field]) latest_embedded_doc = embedded_doc else: # grab the specific version embedded_doc = get_data_version_relation_document( data_relation, document[field]) # grab the latest version latest_embedded_doc = get_data_version_relation_document( data_relation, document[field], latest=True) # make sure we got the documents if embedded_doc is None or latest_embedded_doc is None: # your database is not consistent!!! that is bad abort(404, description=debug_error_message( "Unable to locate embedded documents for '%s'" % field)) # build the response document build_response_document(embedded_doc, data_relation['resource'], [], latest_embedded_doc) else: embedded_doc = app.data.find_one( data_relation['resource'], None, **{config.ID_FIELD: document[field]}) if embedded_doc: document[field] = embedded_doc