server/migractions.py
changeset 6292 054fa36060d5
parent 6217 e2aeb40d5983
child 6333 e3994fcc21c3
--- a/server/migractions.py	Thu Sep 16 18:56:35 2010 +0200
+++ b/server/migractions.py	Tue Sep 21 16:33:20 2010 +0200
@@ -41,6 +41,7 @@
 from glob import glob
 from copy import copy
 from warnings import warn
+from contextlib import contextmanager
 
 from logilab.common.deprecation import deprecated
 from logilab.common.decorators import cached, clear_cache
@@ -48,6 +49,7 @@
 
 from yams.constraints import SizeConstraint
 from yams.schema2sql import eschema2sql, rschema2sql
+from yams.schema import RelationDefinitionSchema
 
 from cubicweb import AuthenticationError, ExecutionError
 from cubicweb.selectors import is_instance
@@ -1116,11 +1118,20 @@
         """synchronize the persistent schema against the current definition
         schema.
 
+        `ertype` can be :
+        - None, in that case everything will be synced ;
+        - a string, it should be an entity type or
+          a relation type. In that case, only the corresponding
+          entities / relations will be synced ;
+        - an rdef object to synchronize only this specific relation definition
+
         It will synch common stuff between the definition schema and the
         actual persistent schema, it won't add/remove any entity or relation.
         """
         assert syncperms or syncprops, 'nothing to do'
         if ertype is not None:
+            if isinstance(ertype, RelationDefinitionSchema):
+                ertype = ertype.as_triple()
             if isinstance(ertype, (tuple, list)):
                 assert len(ertype) == 3, 'not a relation definition'
                 self._synchronize_rdef_schema(ertype[0], ertype[1], ertype[2],
@@ -1377,6 +1388,40 @@
         """add a new entity of the given type"""
         return self.cmd_create_entity(etype, *args, **kwargs).eid
 
+    @contextmanager
+    def cmd_dropped_constraints(self, etype, attrname, cstrtype,
+                                droprequired=False):
+        """context manager to drop constraints temporarily on fs_schema
+
+        `cstrtype` should be a constraint class (or a tuple of classes)
+        and will be passed to isinstance directly
+
+        For instance::
+
+            >>> with dropped_constraints('MyType', 'myattr',
+            ...                          UniqueConstraint, droprequired=True):
+            ...     add_attribute('MyType', 'myattr')
+            ...     # + instructions to fill MyType.myattr column
+            ...
+            >>>
+
+        """
+        rdef = self.fs_schema.eschema(etype).rdef(attrname)
+        original_constraints = rdef.constraints
+        # remove constraints
+        rdef.constraints = [cstr for cstr in original_constraints
+                            if not (cstrtype and isinstance(cstr, cstrtype))]
+        if droprequired:
+            original_cardinality = rdef.cardinality
+            rdef.cardinality = '?' + rdef.cardinality[1]
+        yield
+        # restore original constraints
+        rdef.constraints = original_constraints
+        if droprequired:
+            rdef.cardinality = original_cardinality
+        # update repository schema
+        self.cmd_sync_schema_props_perms(rdef, syncperms=False)
+
     def sqlexec(self, sql, args=None, ask_confirm=True):
         """execute the given sql if confirmed