Ejemplo n.º 1
0
    def _update_tables(self, thing_id, key, olddata, newdata):
        def find_datatype(value):
            if isinstance(value, common.Text):
                return 'text'
            elif isinstance(value, common.Reference):
                return 'ref'
            elif isinstance(value, bool):
                return 'boolean'
            elif isinstance(value, float):
                return 'float'
            elif isinstance(value, int):
                return 'int'
            else:
                return 'str'
                
        def do_action(f, typekey, thing_id, name, value, ordering=None):
            if isinstance(value, list):
                for i, v in enumerate(value):
                    do_action(f, typekey, thing_id, name, v, i)
            elif isinstance(value, dict):
                for k, v in value.items():
                    do_action(f, typekey, thing_id, name + '.' + k, v, ordering)
            else:
                datatype = find_datatype(value)
                if datatype == 'ref':
                    value = self.get_metadata(value)
                    value = value and value.id
                elif datatype == 'str':
                    value = value[:2048] # truncate long strings
                elif isinstance(value, bool):
                    value = "ft"[int(value)] # convert boolean to 't' or 'f'
                table = self.schema.find_table(typekey, datatype, name)
                
                if table:
                    type_id = self.get_metadata(typekey).id
                    pid = self.get_property_id(type_id, name, create=True)
                    assert pid is not None
                    f(table, thing_id, pid, value, ordering)
        
        def action_delete(table, thing_id, key_id, value, ordering):
            self.db.delete(table, where='thing_id=$thing_id AND key_id=$key_id', vars=locals())
        
        def action_insert(table, thing_id, key_id, value, ordering):
            self.db.insert(table, seqname=False, thing_id=thing_id, key_id=key_id, value=value, ordering=ordering)

        old_type = (olddata and olddata['type']) or None
        new_type = newdata['type']
        
        def _coerce(d):
            if isinstance(d, dict) and 'key' in d:
                return d['key']
            else:
                return d
    
        old_type = _coerce(old_type)
        new_type = _coerce(new_type)
        
        for k in ['id', 'key', 'type', 'last_modified', 'created', 'revision']:
            olddata.pop(k, None)
            newdata.pop(k, None)
        
        removed, unchanged, added = common.dict_diff(olddata, newdata)
                
        if old_type != new_type:
            removed = olddata.keys()
            added = newdata.keys()
        
        for k in removed:
            do_action(action_delete, old_type, thing_id, k, olddata[k])
        
        for k in added:
            do_action(action_insert, new_type, thing_id, k, newdata[k])