Commits

Matthew Frazier  committed ca145f8

added validate_changes and post_update callbacks

  • Participants
  • Parent commits b319e0f

Comments (0)

Files changed (5)

File redismap/models/base.py

     
     id = property(attrgetter("_id"), doc="The model's ID.")
     
+    def validate_changes(self, changes):
+        """
+        This passes the changes on to the `Manager` for verification - i.e.,
+        against indexes and the like.
+        """
+        type(self).objects.validate_changes(self, changes)
+    
+    def post_update(self):
+        """
+        This passes the instance on to the `Manager` after updates, so it can
+        update indices and the like.
+        """
+        type(self).objects.post_update(self)
+    
     def delete(self):
         """
         Deletes this `Model`. It delegates to the `Manager` to accomplish

File redismap/models/manager.py

     def allocate_id(self):
         raise ValueError("must provide an id")
     
+    def validate_changes(self, inst, changes):
+        pass
+    
+    def post_update(self, inst):
+        pass
+    
     def exists(self, id):
         return id in self.all_ids
     

File redismap/structure.py

         """
         self._data = self.key.hgetall()
     
+    def validate_changes(self, changes):
+        """
+        This is a callback that can be overridden to perform custom validation
+        on the structure. It is passed `changes`, which is a dictionary of
+        values to be changed. This is called **before** the changes are
+        committed, but after individual fields have been validated.
+        
+        This should not modify the `changes` dictionary (if it does, it will
+        have no effect) and should not make any permanent changes to the
+        database state. It may raise `TypeError`, `ValueError`, or
+        `ValidationError` if there is a problem.
+        """
+    
+    def post_update(self):
+        """
+        This is a callback that can be overridden to perform postprocessing
+        after the structure has been updated. It is passed no arguments. This
+        is called **after** the changes have already been committed and the
+        instance has been refreshed.
+        """
+    
     def update(self, _data=None, **kwargs):
         """
         Updates the given fields atomically. This will validate the fields,
                 converted = field.converter.to_redis(value)
                 field.validate(value)
                 updates[key] = converted
+        self.validate_changes(kwargs)
         if deletes:
             pipe = self.key.client.pipeline(True)
             if updates:
         else:
             self.key.hmset(updates)
         self.refresh()
+        self.post_update()
     
     def all_keys(self):
         keys = [self.key]

File tests/_environment.py

 """
 import os
 import threading
+from contextlib import contextmanager
 from redis import Redis
 from time import sleep, time
 
     
     def __repr__(self):
         return "Timer running for %r" % self.elapsed
+
+
+_signals = {}
+
+def signal(term):
+    _signals[term] = True
+
+
+@contextmanager
+def assert_signaled(*terms):
+    _signals.clear()
+    yield
+    for term in terms:
+        assert _signals.pop(term, False), "signal %s never received" % term

File tests/structure.py

 from redismap import (Key, UTF8, Integer, DateTime, Structure, Field, Set,
                       ValidationError)
 from redismap.redisobject import RedisObject, Definition
-from ._environment import client
+from ._environment import client, signal, assert_signaled
 
 structuretests = Tests()
 
 class Person(Structure):
     name = Field(UTF8, required=True)
     age = Field(Integer, validators=[positive])
+    
+    def validate_changes(self, changes):
+        signal("validate_changes")
+    
+    def post_update(self):
+        signal("post_update")
 
 
 class Status(Structure):
     assert "age" not in person._data
     assert not key.hexists("age")
     # updating
-    person.update(name=u"Guido van Rossum", age=55)
+    with assert_signaled("validate_changes", "post_update"):
+        person.update(name=u"Guido van Rossum", age=55)
     assert person.name == u"Guido van Rossum"
     assert person.age == 55
     assert person._data == {"name": "Guido van Rossum", "age": "55"}