`````````````````
domain/base.py
`````````````````

The `base 
<http://www.async.com.br/projects/stoq/docs/package/public/stoq.domain.base-module.html>`_ 
module has all abstract mixin classes used to build all domain classes.

These classes are mixin for domain components, domain adapters and domain
interfaces. The component model is based on top of twisted components and
the persistent layer use SQLObject to store all domain information on SQL
database.

AbstractModel is the base abstract class of all domain classes: base adapted
classes (Domain, InheritableModel), adapter classes (ModelAdapter,
InheritableModelAdapter).

ComponetizedModel and ConnMetaInterface are especializated versions of base
twisted classes:Componetized and MetaInterface, and have some mofications to 
be used on stoq, and to be compatible with SQLObject.

We need to import modules and classes inherited from classes defined in
stoq/domain/base.py.

    >>> from stoq.lib.runtime import new_transaction
    >>> from stoq.domain.product import Product

Create a new transaction object:

    >>> conn = new_transaction()

Create a new instance of Product class:

    >>> test_product = Product(connection=conn)

To discover what is the name of database table mapped to this domain class
you call the AbstractModel get_db_table_name which is a class method.

    >>> Product.get_db_table_name()
    'product'

All domain classes has an protected attribute to lead with objects that are
created inside a transaction: _is_valid_model.
We have three methods do set valid, set invalid and get this state.

    >>> test_product.get_valid()
    True
    >>> test_product.set_invalid()
    >>> test_product.get_valid()
    False

Now we can set this model valid, verify that that get_valid return true
again. 

    >>> test_product.set_valid()
    >>> test_product.get_valid()
    True

If I call set_valid method on a model wich _is_valid_model is True, it
should raise an exception,

    >>> test_product.set_valid()
    Traceback (most recent call last):
    ValueError: This model is already valid.

To clone a domain class instance, you need to use the clone method.

    >>> test_product_clone = test_product.clone()

This new product is an entire new object and have a different registry on
the database:

    >>> assert test_product is not test_product_clone

To get the current connection of a given instance you must call
get_connection method.

    >>> assert conn is test_product.get_connection()

Cloned instances must have the same connection attribute of your original
instance.

    >>> assert (test_product.get_connection() is
    ...         test_product_clone.get_connection())
    
Import ISellable interface and verify if this Product instance has a
component that implement this interface:

    >>> from stoq.domain.interfaces import ISellable
    >>> ISellable(test_product, connection=conn)

To get the correct Adapter class that implements a given interface you have
to call getAdapterClass method, and never import directly an Adapter class.

    >>> adapter_class = test_product.getAdapterClass(ISellable)
    >>> adapter_class
    <class 'stoq.domain.product.ProductAdaptToSellable'>

To register a new facet you can call registerFacet class method. But
stoq/domain/product.py module alredy registry ProductAdaptToSeallble facet
and thus this another call must raise an exception.

    >>> Product.registerFacet(adapter_class, ISellable)
    Traceback (most recent call last):
    TypeError: Product does already have a facet for interface ISellable

To create a unique code for a ProductAdaptToSellable object, I use datetime
module

    >>> import datetime
    >>> product_code =  'test_code' + str(datetime.datetime.now())

The BaseSellableInfo class stores basic information about sellables. This
object is mandatory for every new sellable.
    
    >>> from stoq.domain.sellable import BaseSellableInfo
    >>> description = 'Red Mustang, 1960'
    >>> sellable_info = BaseSellableInfo(connection=conn,
    ...                                  description=description,
    ...                                  price=1500.45)

To plug an adapter to a given component you have to call addFacet
method.

    >>> adapter = test_product.addFacet(ISellable,
    ...                                 base_sellable_info=sellable_info,
    ...                                 connection=conn,
    ...                                 code=product_code)

Then you can check if the returned instance is of a correct adapter type:

    >>> assert isinstance(adapter, adapter_class)

When you have an adapter instance and need to discover the base component
wich it's pluged, you can call get_adapted method, or get_adapted_id to get
the id of your base class.

    >>> base = adapter.get_adapted()
    >>> assert base is test_product
    >>> base_id = adapter.get_adapted_id()
    >>> assert base_id == test_product.id 
