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)
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)
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
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
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)
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
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, )
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
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()
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