예제 #1
0
 def insert_relation_defs(self):
     cnx = self.cnx
     repo = cnx.repo
     edited_entities = {}
     relations = {}
     for subj, rtype, obj in self.relation_defs():
         # if a string is given into args instead of an int, we get it here
         if isinstance(subj, str):
             subj = int(subj)
         elif not isinstance(subj, int):
             subj = subj.entity.eid
         if isinstance(obj, str):
             obj = int(obj)
         elif not isinstance(obj, int):
             obj = obj.entity.eid
         if repo.schema.rschema(rtype).inlined:
             if subj not in edited_entities:
                 entity = cnx.entity_from_eid(subj)
                 edited = EditedEntity(entity)
                 edited_entities[subj] = edited
             else:
                 edited = edited_entities[subj]
             edited.edited_attribute(rtype, obj)
         else:
             if rtype in relations:
                 relations[rtype].append((subj, obj))
             else:
                 relations[rtype] = [(subj, obj)]
     repo.glob_add_relations(cnx, relations)
     for edited in edited_entities.values():
         repo.glob_update_entity(cnx, edited)
예제 #2
0
    def add_relations(self, relations):
        '''set many relation using a shortcut similar to the one in add_relation

        relations is a list of 2-uples, the first element of each
        2-uple is the rtype, and the second is a list of (fromeid,
        toeid) tuples
        '''
        edited_entities = {}
        relations_dict = {}
        with self.security_enabled(False, False):
            for rtype, eids in relations:
                if self.vreg.schema[rtype].inlined:
                    for fromeid, toeid in eids:
                        if fromeid not in edited_entities:
                            entity = self.entity_from_eid(fromeid)
                            edited = EditedEntity(entity)
                            edited_entities[fromeid] = edited
                        else:
                            edited = edited_entities[fromeid]
                        edited.edited_attribute(rtype, toeid)
                else:
                    relations_dict[rtype] = eids
            self.repo.glob_add_relations(self, relations_dict)
            for edited in edited_entities.values():
                self.repo.glob_update_entity(self, edited)
예제 #3
0
 def base_etype_dicts(self, etype):
     cnx = self._mdgen._cnx
     entity = cnx.vreg['etypes'].etype_class(etype)(cnx)
     # entity are "surface" copied, avoid shared dict between copies
     del entity.cw_extra_kwargs
     entity.cw_edited = EditedEntity(entity)
     attrs = self._mdgen.base_etype_attrs(etype)
     entity.cw_edited.update(attrs, skipsec=False)
     rels = self._mdgen.base_etype_rels(etype)
     return entity, rels
예제 #4
0
 def migrate_entity(self, entity, attribute):
     """migrate an entity attribute to the storage"""
     entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache)
     binary = self.entity_added(entity, attribute)
     if binary is not None:
         cnx = entity._cw
         source = cnx.repo.system_source
         attrs = source.preprocess_entity(entity)
         sql = source.sqlgen.update('cw_' + entity.cw_etype, attrs,
                                    ['cw_eid'])
         source.doexec(cnx, sql, attrs)
     entity.cw_edited = None
예제 #5
0
 def test_clone_cache_reset(self):
     """
     Tests that when an EditedEntity is cloned the caches are reset in the cloned instance
     :return: Nothing
     """
     # Create an entity, create the EditedEntity and clone it
     with self.admin_access.cnx() as cnx:
         affaire = cnx.create_entity("Affaire", sujet=u"toto")
         ee = EditedEntity(affaire)
         ee.entity.cw_adapt_to("IWorkflowable")
         self.assertTrue(ee.entity._cw_related_cache)
         self.assertTrue(ee.entity._cw_adapters_cache)
         the_clone = ee.clone()
         self.assertFalse(the_clone.entity._cw_related_cache)
         self.assertFalse(the_clone.entity._cw_adapters_cache)
         cnx.rollback()
     # Check the attributes
     with self.admin_access.cnx() as cnx:
         # Assume a different connection set on the entity
         self.assertNotEqual(the_clone.entity._cw, cnx)
         # Use the new connection
         the_clone.entity._cw = cnx
         self.assertEqual("toto", the_clone.entity.sujet)
예제 #6
0
 def base_etype_dicts(self, etype):
     entity = self._cnx.vreg['etypes'].etype_class(etype)(self._cnx)
     # entity are "surface" copied, avoid shared dict between copies
     del entity.cw_extra_kwargs
     entity.cw_edited = EditedEntity(entity)
     for attr in self.etype_attrs:
         genfunc = self.generate(attr)
         if genfunc:
             entity.cw_edited.edited_attribute(attr, genfunc(entity))
     rels = {}
     for rel in self.etype_rels:
         genfunc = self.generate(rel)
         if genfunc:
             rels[rel] = genfunc(entity)
     return entity, rels
예제 #7
0
 def build_insert_plan(self, plan, rqlst):
     """get an execution plan from an INSERT RQL query"""
     # each variable in main variables is a new entity to insert
     to_build = {}
     cnx = plan.cnx
     etype_class = cnx.vreg['etypes'].etype_class
     for etype, var in rqlst.main_variables:
         # need to do this since entity class is shared w. web client code !
         to_build[var.name] = EditedEntity(etype_class(etype)(cnx))
         plan.add_entity_def(to_build[var.name])
     # add constant values to entity def, mark variables to be selected
     to_select = _extract_const_attributes(plan, rqlst, to_build)
     # add necessary steps to add relations and update attributes
     step = InsertStep(plan)  # insert each entity and its relations
     step.children += self._compute_relation_steps(plan, rqlst, to_select)
     return (step, )
예제 #8
0
 def execute(self):
     """execute this step"""
     cnx = self.plan.cnx
     repo = cnx.repo
     edefs = {}
     relations = {}
     # insert relations
     if self.children:
         result = self.execute_child()
     else:
         result = [[]]
     for i, row in enumerate(result):
         newrow = []
         for (lhsinfo, rhsinfo, rschema) in self.updatedefs:
             if rschema.rule:
                 raise QueryError("'%s' is a computed relation" %
                                  rschema.type)
             lhsval = _handle_relterm(lhsinfo, row, newrow)
             rhsval = _handle_relterm(rhsinfo, row, newrow)
             if rschema.final or rschema.inlined:
                 eid = int(lhsval)
                 try:
                     edited = edefs[eid]
                 except KeyError:
                     edef = cnx.entity_from_eid(eid)
                     edefs[eid] = edited = EditedEntity(edef)
                 edited.edited_attribute(str(rschema), rhsval)
             else:
                 str_rschema = str(rschema)
                 if str_rschema in relations:
                     relations[str_rschema].append((lhsval, rhsval))
                 else:
                     relations[str_rschema] = [(lhsval, rhsval)]
         result[i] = newrow
     # update entities
     repo.glob_add_relations(cnx, relations)
     for eid, edited in edefs.items():
         repo.glob_update_entity(cnx, edited)
     return result
예제 #9
0
    def process_entities_hooks(self, cnx, entity_hooks):
        source = cnx.repo.system_source

        for hookregid, stuff in entity_hooks:
            for etype, eid_plus_caches in stuff.iteritems():
                entities = []
                etypeclass = cnx.vreg['etypes'].etype_class(etype)

                for eid, cache in eid_plus_caches:
                    entity = etypeclass(cnx)
                    entity.eid = eid
                    entity.cw_attr_cache = cache
                    entity.cw_edited = EditedEntity(entity, **cache)

                    cnx.set_entity_cache(entity)
                    entities.append(entity)

                if hookregid == '__pseudo_entity_fti__':
                    if server.DEBUG & server.DBG_HOOKS:
                        print '%s: fti for %s entities' % (
                            etype, len(eid_plus_caches))
                    for entity in entities:
                        entity.complete(entity.e_schema.indexable_attributes())
                        source.index_entity(cnx, entity=entity)
                    continue

                hookclass, events = self._fetch_hook(cnx, hookregid, 'entity')
                if server.DEBUG & server.DBG_HOOKS:
                    print 'entity hooks: %s %s (%s)' % (etype, hookregid,
                                                        len(entities))
                for entity in entities:
                    assert entity.cw_etype == etype
                    with cnx.security_enabled(read=False, write=False):
                        for event in events:
                            hook = hookclass(cnx, entity=entity, event=event)
                            hook()
예제 #10
0
    def insert_entities(self,
                        etype,
                        entitiesdicts,
                        processentity=None,
                        processattributes=None,
                        _store=False):

        eschema = self.schema[etype]
        etypeclass = self.cnx.vreg['etypes'].etype_class(etype)
        etypeid = eschema.eid
        ancestorseid = [etypeid] + [
            eschema_eid(self.cnx, aschema) for aschema in eschema.ancestors()
        ]

        allkeys = set()
        attributes = []
        binaries = []

        metadata = []
        isrelation = []
        isinstanceof = []
        cw_source = []

        system_source_eid = None
        if self.handle_cw_source_relation:
            system_source_eid = self.cnx.repo.system_source.eid

        entities = []
        bytesrtypes = set(rschema.type
                          for rschema in eschema.subject_relations()
                          if 'Bytes' in rschema.targets())

        utcnow = datetime.utcnow()

        if _store:
            eidsequence = count(0, -1)
        else:
            eidsequence = reserve_eids(self.cnx, len(entitiesdicts))
        for attrs_and_callbackdata, eid in izip(entitiesdicts, eidsequence):

            insertattrs = attrs_and_callbackdata[0]

            # metaattrsinit hook
            insertattrs['creation_date'] = utcnow
            insertattrs['modification_date'] = utcnow
            if 'cwuri' not in insertattrs:
                insertattrs['cwuri'] = unicode(eid)

            if 'eid' not in insertattrs:
                insertattrs['eid'] = eid
            else:
                assert _store
                eid = insertattrs['eid']

            if processattributes:
                processattributes(insertattrs, attrs_and_callbackdata[1])

            attributes.append(insertattrs)
            allkeys |= set(insertattrs)

            # prepare metadata tables
            meta = {'type': etype, 'eid': eid}
            metadata.append(meta)
            isrelation.append({'eid_from': eid, 'eid_to': etypeid})
            for ancestor in ancestorseid:
                isinstanceof.append({'eid_from': eid, 'eid_to': ancestor})

            if system_source_eid:
                cw_source.append({
                    'eid_from': eid,
                    'eid_to': system_source_eid
                })

            # create an entity
            entity = etypeclass(self.cnx)
            entity.eid = eid
            entity.cw_attr_cache = insertattrs
            entity.cw_edited = EditedEntity(entity, **insertattrs)

            self.cnx.set_entity_cache(entity)

            entities.append(entity)

        # give a default value to unvalued attributes
        # after this, all attributes are well defined
        for rtype, default in _iter_attr_default(eschema, utcnow):
            for attr in attributes:
                if rtype not in attr:
                    attr[rtype] = default

        # update the repo.eid_type_source cache
        repo = self.cnx.repo
        for entity in entities:
            repo._type_cache[entity.eid] = entity.cw_etype

        inlinedrtypes = set(rschema.type
                            for rschema in eschema.subject_relations()
                            if rschema.inlined)

        runhooks = not nohook(self.cnx)

        # we compute the smallest possible inlined rtypes set to minimize
        # the work done by the hook
        irtypes = inlinedrtypes.intersection(allkeys)
        if runhooks:
            self.hooksrunner.call_etype_hooks('before_add', etype, entities,
                                              irtypes)

        # Binary -> buffer thing
        if bytesrtypes:
            for insertattrs in attributes:
                binary_or_none = {}
                for rtype in bytesrtypes:
                    data = insertattrs[rtype]
                    binary_or_none[rtype] = data
                    if data is not None:
                        insertattrs[rtype] = buffer(data.getvalue())
                    binaries.append(binary_or_none)

        _insertmany(self.cnx, 'entities', metadata)
        _insertmany(self.cnx, etype, attributes, prefix='cw_')
        _insertmany(self.cnx, 'is_relation', isrelation)
        _insertmany(self.cnx, 'is_instance_of_relation', isinstanceof)
        if cw_source:
            _insertmany(self.cnx, 'cw_source_relation', cw_source)

        if bytesrtypes:
            # wipe the buffer, restore the Binary object
            for binary_or_none, insertattrs in izip(binaries, attributes):
                for rtype, data in binary_or_none.iteritems():
                    insertattrs[rtype] = data

        if processentity is not None:
            for entity, callbackdata in izip(entities, entitiesdicts):
                processentity(entity, *callbackdata)

        user = self.cnx.user
        is_internal = user.login == '__internal_manager__'
        if runhooks:
            self.hooksrunner.call_etype_hooks('after_add', etype, entities,
                                              irtypes)

            # setowner hook
            if not is_internal:
                fromto = tuple((entity, user) for entity in entities)
                self.insert_relations('owned_by',
                                      fromto,
                                      _update_relcache=False)
                self.insert_relations('created_by',
                                      fromto,
                                      _update_relcache=False)

        # avoid an excessive memory consumption: the user is never cleared by
        # cnx.commit() or cnx.clear()
        if not is_internal:
            user._cw_related_cache.clear()

        return entities