Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

Storage Mixer

Dejavu's Storage Managers are not only customizable, but chainable. The CachingProxy? class, for example, can pass requests and data through to any other Storage Manager, effectively caching the data transparently.

Sometimes, you want a Manager that is more aware of its data. For example, I needed to mix Transaction data from two different stores, one for Income and one for Expenses, and treat them as if they came from the same table. Here's an SM which mixes the data from the two sources.

class TransactionMixer(storage.StorageManager):
    """StorageManager for mixing Income from one SM with Expenses from another SM."""
    
    def __init__(self, name, arena, allOptions={}):
        storage.StorageManager.__init__(self, name, arena, allOptions)
        
        self.income_store = arena.stores[allOptions['Income Store']]
        self.expense_store = arena.stores[allOptions['Expense Store']]
    
    def recall(self, unitClass, expr=None):
        for unit in self.income_store.recall(unitClass, expr):
            yield unit
        
        for unit in self.expense_store.recall(unitClass, expr):
            yield unit
    
    def save(self, unit, forceSave=False):
        """Update storage from the Unit's data."""
        if unit.dirty() or forceSave:
            self.store(unit).save(unit, forceSave)
    
    def destroy(self, unit):
        """Delete the unit."""
        self.store(unit).destroy(unit)
    
    def reserve(self, unit):
        self.store(unit).reserve(unit)
    
    def create_storage(self, unitClass):
        self.store(unit).create_storage(unitClass)
    
    def store(self, unit):
        cls = unit.__class__.__name__
        if cls == 'Transaction' and unit.Expense:
            return self.expense_store
        elif cls == 'Ledger' and unit.Transaction().Expense:
            return self.expense_store
        return self.income_store

It's pretty simple; it doesn't handle relocating a Unit from one store to the other, for example. But I didn't have a use case for that. You could certainly build that functionality into your own Storage Manager if necessary. It also requires that Transaction.Expense and Ledger.TransactionID be set correctly, for every call. But that's so much easier to enforce in the presentation layer on a small project, than to solve in the general case in the Storage Manager, that the simpler solution won out.