Exemple #1
0
class Raba(object):
    "All raba object inherit from this class"
    __metaclass__ = _RabaSingleton_MetaClass
    raba_id = RabaFields.Primitive()
    json = RabaFields.Primitive()
    _raba_abstract = True

    def __init__(self, *a, **b):
        pass

    def unreference(self):
        "explicit deletes the object from the singleton reference dictionary. This is mandatory to be able to delete the object using del(). Also, any attempt to reload an object with the same parameters will result un a new instance being created"
        try:
            del (self.__class__._instances[makeRabaObjectSingletonKey(
                self.__class__.__name__, self._raba_namespace, self.raba_id)])
        except KeyError:
            pass

    def _initDbLine(self, dbLine):
        self.raba_id = dbLine[self.__class__.columns['raba_id']]
        self.json = dbLine[self.__class__.columns['json']]

        lists = []
        for kk, i in self.columns.iteritems():
            k = self.columnsToLowerCase[kk.lower()]
            elmt = getattr(self._rabaClass, k)
            if RabaFields.isPrimitiveField(elmt):
                try:
                    self.__setattr__(k, cPickle.loads(str(dbLine[i])))
                except:
                    self.__setattr__(k, dbLine[i])

            elif RabaFields.isRabaObjectField(elmt):
                if dbLine[i] != None:
                    val = json.loads(dbLine[i])
                    objClass = RabaConnection(val["raba_namespace"]).getClass(
                        val["className"])
                    self.__setattr__(k, RabaPupa(objClass, val["raba_id"]))
            elif RabaFields.isRabaListField(elmt):
                if dbLine[i] == None:
                    lists.append((k, 0))
                else:
                    lists.append((k, int(dbLine[i])))
            else:
                raise ValueError(
                    "Unable to set field %s to %s in Raba object %s" %
                    (k, dbLine[i], self._rabaClass.__name__))

        #~ self.rabaLists = []
        for k, leng in lists:
            rlp = RabaListPupa(anchorObj=self, relationName=k, length=leng)
            self.__setattr__(k, rlp)
            self.rabaLists.append(rlp)

    def _raba__init__(self, **fieldsSet):

        self.sqlSave = {}
        self.sqlSaveQMarks = {}
        self.listsToSave = {}
        self.rabaLists = []

        if self.__class__ is Raba:
            raise TypeError(
                'Raba class should never be instanciated, use inheritance')

        self._runtimeId = (
            self.__class__.__name__, random.random()
        )  #this is used only during runtime ex, to avoid circular calls
        self._rabaClass = self.__class__

        self.connection = RabaConnection(self._rabaClass._raba_namespace)
        self.rabaConfiguration = RabaConfiguration(
            self._rabaClass._raba_namespace)

        self._saved = False  #True if present in the database

        if 'initDbLine' in fieldsSet and 'initDbLine' != None:
            self._initDbLine(fieldsSet['initDbLine'])
            self._saved = True

        if self.raba_id == None:
            self.raba_id = self.connection.getNextRabaId(self)

    def pupa(self):
        """returns a pupa version of self"""
        return RabaPupa(self.__class__, self.raba_id)

    def develop(self):
        "Dummy fct, so when you call develop on a full developed object you don't get nasty exceptions"
        pass

    @classmethod
    def _parseIndex(cls, fields):
        con = RabaConnection(cls._raba_namespace)
        ff = []
        rlf = []
        tmpf = []
        if type(fields) is types.StringType:
            tmpf.append(fields)
        else:
            tmpf = fields

        for field in tmpf:
            if RabaFields.isRabaListField(getattr(cls, field)):
                lname = con.makeRabaListTableName(cls.__name__, field)
                rlf.append(lname, )
            else:
                ff.append(field)

        return rlf, ff

    @classmethod
    def ensureIndex(cls, fields, where='', whereValues=[]):
        """Add an index for field, indexes take place and slow down saves and deletes but they speed up a lot everything else. If you are going to do a lot of saves/deletes drop the indexes first re-add them afterwards
		Fields can be a list of fields for Multi-Column Indices or simply the name of a single field. But as RabaList are basicaly in separate tables you cannot create a multicolumn indice on them. A single index will
		be create for the RabaList alone"""
        con = RabaConnection(cls._raba_namespace)
        rlf, ff = cls._parseIndex(fields)
        ww = []
        for i in range(len(whereValues)):
            if isRabaObject(whereValues[i]):
                ww.append(whereValues[i].getJsonEncoding())

        for name in rlf:
            con.createIndex(name, 'anchor_raba_id')

        if len(ff) > 0:
            con.createIndex(cls.__name__, ff, where=where, whereValues=ww)
        con.commit()

    @classmethod
    def dropIndex(cls, fields):
        "removes an index created with ensureIndex "
        con = RabaConnection(cls._raba_namespace)
        rlf, ff = cls._parseIndex(fields)

        for name in rlf:
            con.dropIndex(name, 'anchor_raba_id')

        con.dropIndex(cls.__name__, ff)
        con.commit()

    @classmethod
    def getIndexes(cls):
        "returns a list of the indexes of a class"
        con = RabaConnection(cls._raba_namespace)
        idxs = []
        for idx in con.getIndexes(rabaOnly=True):
            if idx[2] == cls.__name__:
                idxs.append(idx)
            else:
                for k in cls.columns:
                    if RabaFields.isRabaListField(getattr(
                            cls, k)) and idx[2] == con.makeRabaListTableName(
                                cls.__name__, k):
                        idxs.append(idx)
        return idxs

    @classmethod
    def flushIndexes(cls):
        "drops all indexes for a class"
        con = RabaConnection(cls._raba_namespace)
        for idx in cls.getIndexes():
            con.dropIndexByName(idx[1])

    def mutated(self):
        'returns True if the object has changed since the last save'
        return len(self.sqlSave) > 0 or len(self.listsToSave) > 0

    def save(self):
        if self.mutated():
            if not self.raba_id:
                raise ValueError(
                    "Field raba_id of self has the not int value %s therefore i cannot save the object, sorry"
                    % (self, self.raba_id))

            for k, v in self.listsToSave.iteritems():
                v._save()
                self.sqlSave[k] = len(v)
                if not self._saved:  #this dict is only for optimisation purpose for generating the insert sql
                    self.sqlSaveQMarks[k] = '?'

            self.sqlSave['json'] = self.getJsonEncoding()
            if not self._saved:  #this dict is only for optimisation purpose for generating the insert sql
                self.sqlSaveQMarks['json'] = '?'

            if not self._saved:
                values = self.sqlSave.values()
                sql = 'INSERT INTO %s (%s) VALUES (%s)' % (
                    self.__class__.__name__, ', '.join(self.sqlSave.keys()),
                    ', '.join(self.sqlSaveQMarks.values()))
            else:
                values = self.sqlSave.values()
                sql = 'UPDATE %s SET %s = ? WHERE raba_id = ?' % (
                    self.__class__.__name__, ' = ?, '.join(
                        self.sqlSave.keys()))
                values.append(self.raba_id)

            self.connection.execute(sql, values)
            self.connection.commit()
            self._saved = True
            self.sqlSave = {}
            self.sqlSaveQMarks = {}
            self.listsToSave = {}

    def delete(self):
        if self._saved:
            for c in self.columnsToLowerCase.itervalues():
                if isRabaList(getattr(self, c)):
                    getattr(self, c).empty()
            self.connection.delete(table=self.__class__.__name__,
                                   where='raba_id = ?',
                                   values=(self.raba_id, ))
            self.connection.commit()

    def copy(self):
        v = copy.copy(self)
        v.raba_id = None
        return v

    def getDctDescription(self):
        "returns a dict describing the object"
        return {
            'type': RabaFields.RABA_FIELD_TYPE_IS_RABA_OBJECT,
            'className': self._rabaClass.__name__,
            'raba_id': self.raba_id,
            'raba_namespace': self._raba_namespace
        }

    def getJsonEncoding(self):
        "returns a json encoding of self.getDctDescription()"
        return json.dumps(self.getDctDescription())

    def set(self, **args):
        "set multiple values quickly, ex : name = woopy"
        for k, v in args.items():
            setattr(self, k, v)

    def __setattr__(self, k, v):
        "This also keeps track of wich fields have been updated."
        vv = v
        if hasattr(self.__class__, k) and RabaFields.isField(
                getattr(self.__class__, k)):
            vSQL = None
            if not RabaFields.isRabaListField(getattr(self.__class__, k)):
                classType = getattr(self.__class__, k)
                if not classType.check(vv):
                    raise ValueError(
                        "Unable to set '%s' to value '%s'. Constrain function violation"
                        % (k, vv))
                if isRabaObject(vv):
                    vSQL = vv.getJsonEncoding()
                elif isPythonPrimitive(vv):
                    vSQL = vv
                else:
                    vSQL = buffer(cPickle.dumps(vv))

                self.sqlSave[k] = vSQL

                if not self._saved:  #this dict is only for optimisation purpose for generating the insert sql
                    self.sqlSaveQMarks[k] = '?'
            else:
                if not isRabaList(vv) and not isRabaListPupa(vv):
                    try:
                        vv = RabaList(v)
                    except:
                        raise ValueError(
                            "Unable to set '%s' to value '%s'. Value is not a valid RabaList"
                            % (k, vv))

                currList = object.__getattribute__(self, k)
                if not RabaFields.isRabaListField(
                        currList) and vv is not currList and len(currList) > 0:
                    currList.erase()
                    self.connection.unregisterRabalist(
                        anchor_class_name=self.__class__.__name__,
                        anchor_raba_id=self.raba_id,
                        relation_name=k)

                vv._attachToObject(self, k)
                self.listsToSave[
                    k] = vv  #self.sqlSave[k] and self.sqlSaveQMarks[k] are updated in self.save() for lists

        object.__setattr__(self, k, vv)

    def __getattribute__(self, k):
        try:
            elmt = object.__getattribute__(self, k)
            if RabaFields.isRabaListField(elmt):  #if empty
                elmt = RabaListPupa(anchorObj=self, relationName=k, length=-1)
                object.__setattr__(self, k, elmt)
            elif RabaFields.isField(elmt):
                elmt = elmt.default

            return elmt
        except AttributeError:
            return self.__getattr__(k)

    def __getattr__(self, k):
        raise AttributeError('%s has no attribute "%s"' % (repr(self), k))

    def __getitem__(self, k):
        return self.__getattribute__(k)

    def __setitem__(self, k, v):
        self.__setattr__(k, v)

    def __repr__(self):
        return "<Raba obj: %s, raba_id: %s>" % (self._runtimeId, self.raba_id)

    @classmethod
    def getFields(cls):
        """returns a set of the available fields. In order to be able ti securely loop of the fields, "raba_id" and "json" are not included in the set"""
        s = set(cls.columns.keys())
        s.remove('json')
        s.remove('raba_id')
        return s

    @classmethod
    def help(cls):
        "returns a string of lisinting available fields"
        return 'Available fields for %s: %s' % (cls.__name__, ', '.join(
            cls.getFields()))
Exemple #2
0
 class C(Raba):
     _raba_namespace = 'test'
     name = RabaFields.Primitive(default='C')
     a = RabaFields.RabaObject('A')
     _raba_uniques = ['name']