cosmetic
[sfa.git] / sfa / storage / persistentobjs.py
index 66703ab..8ff81ed 100644 (file)
@@ -70,12 +70,6 @@ class AlchemyObj:
         fields=self.fields
         if isinstance(fields,dict): fields=fields.keys()
         return fields
-    def load_from_xml (self, xml):
-        xml_record = XML(xml)
-        xml_dict = xml_record.todict()
-        logger.info("load from xml, keys=%s"%xml_dict.keys())
-        for (k,v) in xml_dict.iteritems():
-            setattr(self,k,v)
 
     def save_as_xml (self):
         # xxx not sure about the scope here
@@ -108,11 +102,16 @@ class AlchemyObj:
 ##############################
 # various kinds of records are implemented as an inheritance hierarchy
 # RegRecord is the base class for all actual variants
+# a first draft was using 'type' as the discriminator for the inheritance
+# but we had to define another more internal column (classtype) so we 
+# accomodate variants in types like authority+am and the like
 
 class RegRecord (Base,AlchemyObj):
     # xxx tmp would be 'records'
     __tablename__       = 'records'
     record_id           = Column (Integer, primary_key=True)
+    # this is the discriminator that tells which class to use
+    classtype           = Column (String)
     type                = Column (String)
     hrn                 = Column (String)
     gid                 = Column (String)
@@ -122,13 +121,12 @@ class RegRecord (Base,AlchemyObj):
     date_created        = Column (DateTime)
     last_updated        = Column (DateTime)
     # use the 'type' column to decide which subclass the object is of
-    __mapper_args__     = { 'polymorphic_on' : type }
+    __mapper_args__     = { 'polymorphic_on' : classtype }
 
     fields = [ 'type', 'hrn', 'gid', 'authority', 'peer_authority' ]
-    def __init__ (self, type='unknown', hrn=None, gid=None, authority=None, peer_authority=None, 
+    def __init__ (self, type=None, hrn=None, gid=None, authority=None, peer_authority=None, 
                   pointer=None, dict=None):
-# managed by alchemy's polymorphic stuff
-#        self.type=type
+        if type:                                self.type=type
         if hrn:                                 self.hrn=hrn
         if gid: 
             if isinstance(gid, StringTypes):    self.gid=gid
@@ -149,7 +147,8 @@ class RegRecord (Base,AlchemyObj):
 
     @validates ('gid')
     def validate_gid (self, key, gid):
-        if isinstance(gid, StringTypes):    return gid
+        if gid is None:                     return
+        elif isinstance(gid, StringTypes):  return gid
         else:                               return gid.save_to_string(save_parents=True)
 
     # xxx - there might be smarter ways to handle get/set'ing gid using validation hooks 
@@ -210,26 +209,10 @@ class RegNode (RegRecord):
     def __repr__ (self):
         return RegRecord.__repr__(self).replace("Record","Node")
 
-# because we use 'type' as the discriminator here, the only way to have type set to
-# e.g. authority+sa is to define a separate class
-# this currently is not used at all though, just to check if all this stuff really is useful
-# if so it would make more sense to store that in the authorities table instead
-class RegTmpAuthSa (RegRecord):
-    __tablename__       = 'authorities_sa'
-    __mapper_args__     = { 'polymorphic_identity' : 'authority+sa' }
-    record_id           = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
-
-class RegTmpAuthAm (RegRecord):
-    __tablename__       = 'authorities_am'
-    __mapper_args__     = { 'polymorphic_identity' : 'authority+am' }
-    record_id           = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
-
-class RegTmpAuthSm (RegRecord):
-    __tablename__       = 'authorities_sm'
-    __mapper_args__     = { 'polymorphic_identity' : 'authority+sm' }
-    record_id           = Column (Integer, ForeignKey ("records.record_id"), primary_key=True)
-
 ##############################
+# although the db needs of course to be reachable,
+# the schema management functions are here and not in alchemy
+# because the actual details of the classes need to be known
 def init_tables(dbsession):
     logger.info("Initializing db schema and builtin types")
     # the doc states we could retrieve the engine this way
@@ -246,10 +229,17 @@ def drop_tables(dbsession):
     from sfa.storage.alchemy import engine
     Base.metadata.drop_all(engine)
 
+##############################
+# create a record of the right type from either a dict or an xml string
+def make_record (dict={}, xml=""):
+    if dict:    return make_record_dict (dict)
+    elif xml:   return make_record_xml (xml)
+    else:       raise Exception("make_record has no input")
+
 # convert an incoming record - typically from xmlrpc - into an object
-def make_record (record_dict):
+def make_record_dict (record_dict):
     assert ('type' in record_dict)
-    type=record_dict['type']
+    type=record_dict['type'].split('+')[0]
     if type=='authority':
         result=RegAuthority (dict=record_dict)
     elif type=='user':
@@ -266,4 +256,8 @@ def make_record (record_dict):
     # register non-db attributes in an extensions field
     return result
         
-        
+def make_record_xml (xml):
+    xml_record = XML(xml)
+    xml_dict = xml_record.todict()
+    logger.info("load from xml, keys=%s"%xml_dict.keys())
+    return make_record_dict (xml_dict)