Ejemplo n.º 1
0
def test_setToi():
    class TO(Fake):
        _fullname = 'blm.TO'
        _attributes = 'attr1', 'attr2', 'attr3', 'attr4'
        def __getattr__(self, attrName):
            return Fake(value=self._attrData.get(attrName, []),
                        default={} if attrName == 'attr4' else [])
        @property
        def _modified(self):
            return set(self._orgAttrData)

    toi = TO(id=[42],
             _attrData={'attr1': ['changed'],
                        'attr2': ['new'],
                        'attr3': ['same'],
                        'attr4': {'foo': 'bar'}},
             _orgAttrData={'attr1': ['old'],
                           'attr2': [],
                           'attr4': {}})
    toiDiff = difftoi.DiffTOI()
    toiDiff.setToi(toi)

    assert toiDiff.toid == 42
    assert toiDiff.toc_fullname == 'blm.TO'
    assert toiDiff.diffAttrs == {'attr1': ['changed'],
                                 'attr2': ['new'],
                                 'attr4': {'foo': 'bar'}}
    assert toiDiff.orgAttrs == {'attr1': ['old'],
                                'attr2': [],
                                'attr4': {}}
Ejemplo n.º 2
0
def test_serializable():
    dt = difftoi.DiffTOI()
    dt.toid = toid = bson.objectid.ObjectId()
    dt.toc = object()
    dt.toc_fullname = 'TO'
    dt.diffAttrs = {'foo': [1], 'bar': [2]}
    data = {'difftoi': dt}
    son = bson.BSON.encode(data)
    decoded = son.decode()
    assert decoded == data
Ejemplo n.º 3
0
def test_matchOld():
    toc = Fake(_fullname='blm.toc', _attributes=['foo', 'bar'])
    toi = Fake(foo=['bar'], baz=['qux'])
    toiDiff = difftoi.DiffTOI()
    toiDiff.setAttrDiff(toc, 42, toi.__dict__, {'foo': ['apa']})

    assert not toiDiff.diffsOld(toi)

    toi.foo = ['apa']
    assert toiDiff.diffsOld(toi) == {'foo': (['apa'], ['bar'])}
Ejemplo n.º 4
0
    def _run(self, params, state):
        toid = params['toid'] = ObjectId(params.get('toid'))
        query = blm.TO._query(id=toid)
        query.attrList = attrList = params['attrList']
        toi = query.run()
        if not toi:
            self.update({'error' : exceptions.ToiNonexistantError(
                        'TO', toid)})
            return

        persistent = params.get('subscription', False)

        toi, = toi
        diffOb = difftoi.DiffTOI()
        attrData = dict([(x, getattr(toi, x).value) for x in attrList])

        diffOb.setDiff(toi.__class__, str(toi.id[0]),
                       state or {}, {}, attrData, {})

        for value in reduce(concat_values, iter(diffOb.diffAttrs.values()), []):
            if isinstance(value, Attribute.BlobVal):
                value.addref(self.clientId)
                if persistent:
                    value.addref(self.link['_id'])

        for value in reduce(concat_values, iter(diffOb.orgAttrs.values()), []):
            if isinstance(value, Attribute.BlobVal):
                value.addref(self.clientId)
                value.delref(self.link['_id'])

        # if this is the first update (state is None) or there's new data...
        update = None
        if state is None or diffOb.diffAttrs:
            update = {'toiDiff': diffOb, 'error': None}
        self.update(update, persistent=persistent)
        if persistent:
            self.save(params, attrData)
Ejemplo n.º 5
0
    def _run(self, params, state):
        criteria = params['criteria']
        sorting = params.get('sorting')
        clientAttrs = set(params.get('attrList', []))
        neededAttrs = set(clientAttrs)

        if sorting:
            sortingAttrs = getattr(criteria.toc, 'sort_%s_attrs' % sorting, [])
            neededAttrs.update(sortingAttrs)

        for attrName in neededAttrs.copy():
            attr = getattr(criteria.toc, attrName)
            extra = getattr(attr, 'extraAttrs', [])
            neededAttrs.update(extra)

        criteria.attrList = neededAttrs

        changedIds =  self.link.get('outdatedToids', [])
        optimize = bool(state and
                        not criteria.hasSubQuery() and
                        not criteria.hasFulltext() and
                        (changedIds or 'update' in state))
        start = time.time()
        if optimize:
            log.debug('Using optimized sorted query recalculation for %s', self)
            tois = set()
            for toid, attrData in state['tois'].items():
                toi = criteria.toc._create(toid, kw=attrData) # xxx
                tois.add(toi)

            if changedIds:
                changedToisQuery = query.Query(criteria.toc, id=changedIds)
                changedToisQuery.attrList = neededAttrs
                changedTois = ContextBroker().runQuery(changedToisQuery)
            else:
                changedTois = []

            def getter(toi, attr):
                if attr == 'id':
                    return list(map(str, toi.id))
                value = getattr(toi, attr.name).value
                if isinstance(attr, Attribute.ToiRef):
                    # Code fighting code:
                    # The conds for toiref attributes will contain
                    # sets of unicode strings representing toids.
                    # The .matches() of respective operators mostly
                    # use set matching operators, so we need to spit
                    # out objects with the same hash as what's in the
                    # conds - thus TOIs themselves are no good.
                    value = [str(toi.id[0]) for toi in value]
                return value

            unhandled = set(changedIds)
            for changedToi in changedTois:
                unhandled.discard(changedToi.id[0])
                if criteria.matches(changedToi, getter):
                    tois.add(changedToi)
                else:
                    tois.discard(changedToi)
            # toids left in unhandled have been removed
            tois = [toi for toi in tois if toi.id[0] not in unhandled]
        else:
            tois = ContextBroker().runQuery(criteria)
        end = time.time()
        _state = state or {}
        opt_log.debug('%s %f %d %d %s %s', optimize, end - start,
                      len(_state.get('tois', [])), len(tois),
                      bool(self.link.get('outdatedBy')), self)

        if sorting:
            sorter = getattr(criteria.toc, 'sort_'+sorting+'_key')
            #import pdb;pdb.set_trace()
            tois.sort(key=sorter)

        persistent = params.get('subscription')

        toiDiffs = {}
        state = state or { 'query': [], 'tois' : {} }
        result = { 'query' : tois, 'tois' : {}, 'order': [] }
        newBlobVals = set()
        for toi in tois:
            diffOb = difftoi.DiffTOI()
            clientData = dict((x, getattr(toi, x).value) for x in clientAttrs)
            neededData = dict((x, getattr(toi, x).value) for x in neededAttrs)
            toid = str(toi.id[0])
            result['tois'][toid] = neededData
            result['order'].append(toid)

            diffOb.setDiff(toi.__class__, toid,
                           state['tois'].get(toid,{}), {}, clientData, {})
            if diffOb.diffAttrs:
                toiDiffs[toid] = diffOb

                for value in reduce(concat_values,
                                    iter(diffOb.diffAttrs.values()), []):
                    if isinstance(value, Attribute.BlobVal):
                        value.addref(self.clientId)
                        newBlobVals.add(value)

                for value in reduce(concat_values,
                                    iter(diffOb.orgAttrs.values()), []):
                    if isinstance(value, Attribute.BlobVal):
                        value.addref(self.clientId)

        oldBlobVals = set()
        for toid, attrData in state['tois'].items():
            for value in reduce(concat_values, iter(attrData.values()), []):
                if isinstance(value, Attribute.BlobVal):
                    oldBlobVals.add(value)

        for blobVal in newBlobVals - oldBlobVals:
            blobVal.addref(self.link['_id'])

        for blobVal in oldBlobVals - newBlobVals:
            blobVal.delref(self.link['_id'])

        update = None
        if state != result:
            log.debug('Updating %s', self)
            diffops = diff.diff_opcodes(state['query'], tois)
            update = { 'diffops' : diffops,
                       'toiDiffs' : toiDiffs,
                       'error': None }
        def updatelink(doc):
            doc.setdefault('$set', {})['outdatedToids'] = []
        self.update(update, persistent, updatelink)
        if persistent:
            self.save(params, result)