hms_core.co_objects.Product

The corresponding Story for concrete Product object data persistence is as follows:

  • As a product manager, I need to be able to manage products in the system, so that their statuses and information can be kept current.

The code that fulfills this scenario is even simpler than the code for Artisan objects; it doesn't need any special handling of object properties, so from_data_dict can simply fall back to the default, defined in HMSMongoDataObject. It doesn't have any extraneous methods that are required, either, so a full, functional implementation really just boils down to the _data_dict_keys class attribute and the __init__, matchesand to_data_dict methods, with matches being implemented as a call to HMSMongoDataObject.matches:

class Product(BaseProduct, HMSMongoDataObject):
    """
Represents a Product in the context of the Central Office 
applications and services
"""
    ###################################
    # Class attributes/constants      #
    ###################################

    _data_dict_keys = [
        'name', 'summary', 'available', 'store_available', 
        'description', 'dimensions', 'metadata', 'shipping_weight', 
        'oid', 'created', 'modified', 'is_active', 'is_deleted'
    ]

The __init__ method has a long argument set, which should come as no surprise:

    ###################################
    # Object initialization           #
    ###################################

    def __init__(self,
        # - Arguments from HMSMongoDataObject
        name:(str,), summary:(str,), available:(bool,), 
        store_available:(bool,), 
        # - Optional arguments:
        description:(str,None)=None, dimensions:(str,None)=None,
        metadata:(dict,)={}, shipping_weight:(int,)=0, 
        # - Arguments from HMSMongoDataObject
        oid:(UUID,str,None)=None, 
        created:(datetime,str,float,int,None)=None, 
        modified:(datetime,str,float,int,None)=None,
        is_active:(bool,int,None)=None, 
        is_deleted:(bool,int,None)=None,
        is_dirty:(bool,int,None)=None, 
        is_new:(bool,int,None)=None,
    ):
        """
Object initialization.

self .............. (Product instance, required) The instance to 
                    execute against
name .............. (str, required) The name of the product
summary ........... (str, required) A one-line summary of the 
                    product
available ......... (bool, required) Flag indicating whether the 
                    product is considered available by the artisan 
                    who makes it
store_available ... (bool, required) Flag indicating whether the 
                    product is considered available on the web-
                    store by the Central Office
description ....... (str, optional, defaults to None) A detailed 
                    description of the product
dimensions ........ (str, optional, defaults to None) A measurement-
                    description of the product
metadata .......... (dict, optional, defaults to {}) A collection 
                    of metadata keys and values describing the 
                    product
shipping_weight ... (int, optional, defaults to 0) The shipping-
                    weight of the product
oid ............... (UUID|str, optional, defaults to None) The unique 
                    identifier of the object's state-data record in the 
                    back-end data-store
created ........... (datetime|str|float|int, optional, defaults to None) 
                    The date/time that the object was created
modified .......... (datetime|str|float|int, optional, defaults to None) 
                    The date/time that the object was last modified
is_active ......... (bool|int, optional, defaults to None) A flag 
                    indicating that the object is active
is_deleted ........ (bool|int, optional, defaults to None) A flag 
                    indicating that the object should be considered 
                    deleted (and may be in the near future)
is_dirty .......... (bool|int, optional, defaults to None) A flag 
                    indicating that the object's data needs to be 
                    updated in the back-end data-store
is_new ............ (bool|int, optional, defaults to None) A flag 
                    indicating that the object's data needs to be 
                    created in the back-end data-store
"""
        # - Call parent initializers if needed
        BaseProduct.__init__(
            self, name, summary, available, store_available, 
            description, dimensions, metadata, shipping_weight
        )
        HMSMongoDataObject.__init__(self, 
            oid, created, modified, is_active, is_deleted, 
            is_dirty, is_new
        )
        # - Perform any other initialization needed

The implementations of matches and to_data_dict are very straightforward, as follows:

    ###################################
    # Instance methods                #
    ###################################

    def matches(self, **criteria) -> (bool,):
        return HMSMongoDataObject.matches(self, **criteria)

    def to_data_dict(self):
        return {
            # - BaseProduct-derived items
            'available':self.available,
            'description':self.description,
            'dimensions':self.dimensions,
            'metadata':self.metadata,
            'name':self.name,
            'shipping_weight':self.shipping_weight,
            'store_available':self.store_available,
            'summary':self.summary,
            # - BaseDataObject-derived items
            'created':datetime.strftime(
                self.created, self.__class__._data_time_string
            ),
            'is_active':self.is_active,
            'is_deleted':self.is_deleted,
            'modified':datetime.strftime(
                self.modified, self.__class__._data_time_string
            ),
            'oid':str(self.oid),
        }

The matches method may need to be reexamined later on, either during the creation of the Artisan Gateway service or when the various application UIs are being built, because while it works for most cases, it will not currently allow a get with any metadata criteria to return results unless criteria is the only value being searched for (no oids are passed). It's worth a more detailed look here and now, though, because it shows some aspects of how the data object code interacts with MongoDB.

First, let's create some example Product objects and save them, as follows:

# - An example product - A copper-and-emerald necklace:
product = Product(
    'Necklace #1', 
    'Showing some Product.get aspects', True, True,
    metadata={
        'metal':'Copper',
        'gemstone':'Emerald',
    }
)
product.save()
# - Silver-and-emerald necklace:
product = Product(
    'Necklace #2', 
    'Showing some Product.get aspects', True, True,
    metadata={
        'metal':'Silver',
        'gemstone':'Emerald',
    }
)
product.save()
# - Copper-and-sapphire necklace:
product = Product(
    'Necklace #3', 
    'Showing some Product.get aspects', True, True,
    metadata={
        'metal':'Copper',
        'gemstone':'Sapphire',
    }
)
product.save()
# - Silver-and-sapphire necklace:
product = Product(
    'Necklace #4', 
    'Showing some Product.get aspects', True, True,
    metadata={
        'metal':'Silver',
        'gemstone':'Sapphire',
    }
)
product.save()

Finding products that have metadata indicating that they are made of silver and have sapphire gemstones is fairly straightforward, although it requires criteria specifications that look a little odd:

# - importing json so we can usefully print the results:
import json
criteria = {
    'metadata':{
        'metal':'Silver',
        'gemstone':'Sapphire',
        }
}

Creating the criteria as a dict allows them to be passed to Product.get as a single keyword argument set, and allows the criteria specification to be as detailed as we need. We could, for example, add other metadata, specify a product name, or add any other object properties that appear in the data-dict representation of a Product (as returned by to_data_dict). The results will come back as a list of objects, and, by printing the data-dict representations of them, we can see the results:

products = Product.get(**criteria)
print(json.dumps(
    [product.to_data_dict() for product in products], 
    indent=4, sort_keys=True)
)

Executing the preceding code yields the dataset for the one matching the Product, our silver and sapphire necklace, as follows:

It's worth mentioning that passing criteria doesn't have to be a multi-level dict, even for metadata values. Using criteria in this format is as follows:

criteria = {
    'metadata.metal':'Silver',
    'metadata.gemstone':'Sapphire',
}

This criteria structure works just as well. The underlying find() method provided by a pymongo connection object treats dot-notation specifications of this sort as references to a nested object structure that looks much like the dict value shown previously, and will process the request accordingly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.62.105