262 if self.config.free_wheel: |
264 if self.config.free_wheel: |
263 self.repo.hm.register_hook(setowner_after_add_entity, |
265 self.repo.hm.register_hook(setowner_after_add_entity, |
264 'after_add_entity', '') |
266 'after_add_entity', '') |
265 self.reactivate_verification_hooks() |
267 self.reactivate_verification_hooks() |
266 |
268 |
267 # base actions ############################################################ |
269 # schema synchronization internals ######################################## |
268 |
270 |
269 def checkpoint(self): |
271 def _synchronize_permissions(self, ertype): |
270 """checkpoint action""" |
|
271 if self.confirm('commit now ?', shell=False): |
|
272 self.commit() |
|
273 |
|
274 def cmd_add_cube(self, cube, update_database=True): |
|
275 self.cmd_add_cubes( (cube,), update_database) |
|
276 |
|
277 def cmd_add_cubes(self, cubes, update_database=True): |
|
278 """update_database is telling if the database schema should be updated |
|
279 or if only the relevant eproperty should be inserted (for the case where |
|
280 a cube has been extracted from an existing application, so the |
|
281 cube schema is already in there) |
|
282 """ |
|
283 newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes) |
|
284 if not newcubes: |
|
285 return |
|
286 for pack in newcubes: |
|
287 self.cmd_set_property('system.version.'+pack, |
|
288 self.config.cube_version(pack)) |
|
289 if not update_database: |
|
290 self.commit() |
|
291 return |
|
292 newcubes_schema = self.config.load_schema(construction_mode='non-strict') |
|
293 new = set() |
|
294 # execute pre-create files |
|
295 for pack in reversed(newcubes): |
|
296 self.exec_event_script('precreate', self.config.cube_dir(pack)) |
|
297 # add new entity and relation types |
|
298 for rschema in newcubes_schema.relations(): |
|
299 if not rschema in self.repo.schema: |
|
300 self.cmd_add_relation_type(rschema.type) |
|
301 new.add(rschema.type) |
|
302 for eschema in newcubes_schema.entities(): |
|
303 if not eschema in self.repo.schema: |
|
304 self.cmd_add_entity_type(eschema.type) |
|
305 new.add(eschema.type) |
|
306 # check if attributes has been added to existing entities |
|
307 for rschema in newcubes_schema.relations(): |
|
308 existingschema = self.repo.schema.rschema(rschema.type) |
|
309 for (fromtype, totype) in rschema.iter_rdefs(): |
|
310 if existingschema.has_rdef(fromtype, totype): |
|
311 continue |
|
312 # check we should actually add the relation definition |
|
313 if not (fromtype in new or totype in new or rschema in new): |
|
314 continue |
|
315 self.cmd_add_relation_definition(str(fromtype), rschema.type, |
|
316 str(totype)) |
|
317 # execute post-create files |
|
318 for pack in reversed(newcubes): |
|
319 self.exec_event_script('postcreate', self.config.cube_dir(pack)) |
|
320 self.commit() |
|
321 |
|
322 def cmd_remove_cube(self, cube): |
|
323 removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(cube) |
|
324 if not removedcubes: |
|
325 return |
|
326 fsschema = self.fs_schema |
|
327 removedcubes_schema = self.config.load_schema(construction_mode='non-strict') |
|
328 reposchema = self.repo.schema |
|
329 # execute pre-remove files |
|
330 for pack in reversed(removedcubes): |
|
331 self.exec_event_script('preremove', self.config.cube_dir(pack)) |
|
332 # remove cubes'entity and relation types |
|
333 for rschema in fsschema.relations(): |
|
334 if not rschema in removedcubes_schema and rschema in reposchema: |
|
335 self.cmd_drop_relation_type(rschema.type) |
|
336 for eschema in fsschema.entities(): |
|
337 if not eschema in removedcubes_schema and eschema in reposchema: |
|
338 self.cmd_drop_entity_type(eschema.type) |
|
339 for rschema in fsschema.relations(): |
|
340 if rschema in removedcubes_schema and rschema in reposchema: |
|
341 # check if attributes/relations has been added to entities from |
|
342 # other cubes |
|
343 for fromtype, totype in rschema.iter_rdefs(): |
|
344 if not removedcubes_schema[rschema.type].has_rdef(fromtype, totype) and \ |
|
345 reposchema[rschema.type].has_rdef(fromtype, totype): |
|
346 self.cmd_drop_relation_definition( |
|
347 str(fromtype), rschema.type, str(totype)) |
|
348 # execute post-remove files |
|
349 for pack in reversed(removedcubes): |
|
350 self.exec_event_script('postremove', self.config.cube_dir(pack)) |
|
351 self.rqlexec('DELETE CWProperty X WHERE X pkey %(pk)s', |
|
352 {'pk': u'system.version.'+pack}, ask_confirm=False) |
|
353 self.commit() |
|
354 |
|
355 # schema migration actions ################################################ |
|
356 |
|
357 def cmd_add_attribute(self, etype, attrname, attrtype=None, commit=True): |
|
358 """add a new attribute on the given entity type""" |
|
359 if attrtype is None: |
|
360 rschema = self.fs_schema.rschema(attrname) |
|
361 attrtype = rschema.objects(etype)[0] |
|
362 self.cmd_add_relation_definition(etype, attrname, attrtype, commit=commit) |
|
363 |
|
364 def cmd_drop_attribute(self, etype, attrname, commit=True): |
|
365 """drop an existing attribute from the given entity type |
|
366 |
|
367 `attrname` is a string giving the name of the attribute to drop |
|
368 """ |
|
369 rschema = self.repo.schema.rschema(attrname) |
|
370 attrtype = rschema.objects(etype)[0] |
|
371 self.cmd_drop_relation_definition(etype, attrname, attrtype, commit=commit) |
|
372 |
|
373 def cmd_rename_attribute(self, etype, oldname, newname, commit=True): |
|
374 """rename an existing attribute of the given entity type |
|
375 |
|
376 `oldname` is a string giving the name of the existing attribute |
|
377 `newname` is a string giving the name of the renamed attribute |
|
378 """ |
|
379 eschema = self.fs_schema.eschema(etype) |
|
380 attrtype = eschema.destination(newname) |
|
381 # have to commit this first step anyway to get the definition |
|
382 # actually in the schema |
|
383 self.cmd_add_attribute(etype, newname, attrtype, commit=True) |
|
384 # skipp NULL values if the attribute is required |
|
385 rql = 'SET X %s VAL WHERE X is %s, X %s VAL' % (newname, etype, oldname) |
|
386 card = eschema.rproperty(newname, 'cardinality')[0] |
|
387 if card == '1': |
|
388 rql += ', NOT X %s NULL' % oldname |
|
389 self.rqlexec(rql, ask_confirm=self.verbosity>=2) |
|
390 self.cmd_drop_attribute(etype, oldname, commit=commit) |
|
391 |
|
392 def cmd_add_entity_type(self, etype, auto=True, commit=True): |
|
393 """register a new entity type |
|
394 |
|
395 in auto mode, automatically register entity's relation where the |
|
396 targeted type is known |
|
397 """ |
|
398 applschema = self.repo.schema |
|
399 if etype in applschema: |
|
400 eschema = applschema[etype] |
|
401 if eschema.is_final(): |
|
402 applschema.del_entity_type(etype) |
|
403 else: |
|
404 eschema = self.fs_schema.eschema(etype) |
|
405 confirm = self.verbosity >= 2 |
|
406 # register the entity into CWEType |
|
407 self.rqlexecall(ss.eschema2rql(eschema), ask_confirm=confirm) |
|
408 # add specializes relation if needed |
|
409 self.rqlexecall(ss.eschemaspecialize2rql(eschema), ask_confirm=confirm) |
|
410 # register groups / permissions for the entity |
|
411 self.rqlexecall(ss.erperms2rql(eschema, self.group_mapping()), |
|
412 ask_confirm=confirm) |
|
413 # register entity's attributes |
|
414 for rschema, attrschema in eschema.attribute_definitions(): |
|
415 # ignore those meta relations, they will be automatically added |
|
416 if rschema.type in ('eid', 'creation_date', 'modification_date'): |
|
417 continue |
|
418 if not rschema.type in applschema: |
|
419 # need to add the relation type and to commit to get it |
|
420 # actually in the schema |
|
421 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
422 # register relation definition |
|
423 self.rqlexecall(ss.rdef2rql(rschema, etype, attrschema.type), |
|
424 ask_confirm=confirm) |
|
425 if auto: |
|
426 # we have commit here to get relation types actually in the schema |
|
427 self.commit() |
|
428 added = [] |
|
429 for rschema in eschema.subject_relations(): |
|
430 # attribute relation have already been processed and |
|
431 # 'owned_by'/'created_by' will be automatically added |
|
432 if rschema.final or rschema.type in ('owned_by', 'created_by', 'is', 'is_instance_of'): |
|
433 continue |
|
434 rtypeadded = rschema.type in applschema |
|
435 for targetschema in rschema.objects(etype): |
|
436 # ignore relations where the targeted type is not in the |
|
437 # current application schema |
|
438 targettype = targetschema.type |
|
439 if not targettype in applschema and targettype != etype: |
|
440 continue |
|
441 if not rtypeadded: |
|
442 # need to add the relation type and to commit to get it |
|
443 # actually in the schema |
|
444 added.append(rschema.type) |
|
445 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
446 rtypeadded = True |
|
447 # register relation definition |
|
448 # remember this two avoid adding twice non symetric relation |
|
449 # such as "Emailthread forked_from Emailthread" |
|
450 added.append((etype, rschema.type, targettype)) |
|
451 self.rqlexecall(ss.rdef2rql(rschema, etype, targettype), |
|
452 ask_confirm=confirm) |
|
453 for rschema in eschema.object_relations(): |
|
454 rtypeadded = rschema.type in applschema or rschema.type in added |
|
455 for targetschema in rschema.subjects(etype): |
|
456 # ignore relations where the targeted type is not in the |
|
457 # current application schema |
|
458 targettype = targetschema.type |
|
459 # don't check targettype != etype since in this case the |
|
460 # relation has already been added as a subject relation |
|
461 if not targettype in applschema: |
|
462 continue |
|
463 if not rtypeadded: |
|
464 # need to add the relation type and to commit to get it |
|
465 # actually in the schema |
|
466 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
467 rtypeadded = True |
|
468 elif (targettype, rschema.type, etype) in added: |
|
469 continue |
|
470 # register relation definition |
|
471 self.rqlexecall(ss.rdef2rql(rschema, targettype, etype), |
|
472 ask_confirm=confirm) |
|
473 if commit: |
|
474 self.commit() |
|
475 |
|
476 def cmd_drop_entity_type(self, etype, commit=True): |
|
477 """unregister an existing entity type |
|
478 |
|
479 This will trigger deletion of necessary relation types and definitions |
|
480 """ |
|
481 # XXX what if we delete an entity type which is specialized by other types |
|
482 # unregister the entity from CWEType |
|
483 self.rqlexec('DELETE CWEType X WHERE X name %(etype)s', {'etype': etype}, |
|
484 ask_confirm=self.verbosity>=2) |
|
485 if commit: |
|
486 self.commit() |
|
487 |
|
488 def cmd_rename_entity_type(self, oldname, newname, commit=True): |
|
489 """rename an existing entity type in the persistent schema |
|
490 |
|
491 `oldname` is a string giving the name of the existing entity type |
|
492 `newname` is a string giving the name of the renamed entity type |
|
493 """ |
|
494 self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(oldname)s', |
|
495 {'newname' : unicode(newname), 'oldname' : oldname}) |
|
496 if commit: |
|
497 self.commit() |
|
498 |
|
499 def cmd_add_relation_type(self, rtype, addrdef=True, commit=True): |
|
500 """register a new relation type named `rtype`, as described in the |
|
501 schema description file. |
|
502 |
|
503 `addrdef` is a boolean value; when True, it will also add all relations |
|
504 of the type just added found in the schema definition file. Note that it |
|
505 implies an intermediate "commit" which commits the relation type |
|
506 creation (but not the relation definitions themselves, for which |
|
507 committing depends on the `commit` argument value). |
|
508 |
|
509 """ |
|
510 rschema = self.fs_schema.rschema(rtype) |
|
511 # register the relation into CWRType and insert necessary relation |
|
512 # definitions |
|
513 self.rqlexecall(ss.rschema2rql(rschema, addrdef=False), |
|
514 ask_confirm=self.verbosity>=2) |
|
515 # register groups / permissions for the relation |
|
516 self.rqlexecall(ss.erperms2rql(rschema, self.group_mapping()), |
|
517 ask_confirm=self.verbosity>=2) |
|
518 if addrdef: |
|
519 self.commit() |
|
520 self.rqlexecall(ss.rdef2rql(rschema), |
|
521 ask_confirm=self.verbosity>=2) |
|
522 if commit: |
|
523 self.commit() |
|
524 |
|
525 def cmd_drop_relation_type(self, rtype, commit=True): |
|
526 """unregister an existing relation type""" |
|
527 # unregister the relation from CWRType |
|
528 self.rqlexec('DELETE CWRType X WHERE X name %r' % rtype, |
|
529 ask_confirm=self.verbosity>=2) |
|
530 if commit: |
|
531 self.commit() |
|
532 |
|
533 def cmd_rename_relation(self, oldname, newname, commit=True): |
|
534 """rename an existing relation |
|
535 |
|
536 `oldname` is a string giving the name of the existing relation |
|
537 `newname` is a string giving the name of the renamed relation |
|
538 """ |
|
539 self.cmd_add_relation_type(newname, commit=True) |
|
540 self.rqlexec('SET X %s Y WHERE X %s Y' % (newname, oldname), |
|
541 ask_confirm=self.verbosity>=2) |
|
542 self.cmd_drop_relation_type(oldname, commit=commit) |
|
543 |
|
544 def cmd_add_relation_definition(self, subjtype, rtype, objtype, commit=True): |
|
545 """register a new relation definition, from its definition found in the |
|
546 schema definition file |
|
547 """ |
|
548 rschema = self.fs_schema.rschema(rtype) |
|
549 if not rtype in self.repo.schema: |
|
550 self.cmd_add_relation_type(rtype, addrdef=False, commit=True) |
|
551 self.rqlexecall(ss.rdef2rql(rschema, subjtype, objtype), |
|
552 ask_confirm=self.verbosity>=2) |
|
553 if commit: |
|
554 self.commit() |
|
555 |
|
556 def cmd_drop_relation_definition(self, subjtype, rtype, objtype, commit=True): |
|
557 """unregister an existing relation definition""" |
|
558 rschema = self.repo.schema.rschema(rtype) |
|
559 # unregister the definition from CWAttribute or CWRelation |
|
560 if rschema.is_final(): |
|
561 etype = 'CWAttribute' |
|
562 else: |
|
563 etype = 'CWRelation' |
|
564 rql = ('DELETE %s X WHERE X from_entity FE, FE name "%s",' |
|
565 'X relation_type RT, RT name "%s", X to_entity TE, TE name "%s"') |
|
566 self.rqlexec(rql % (etype, subjtype, rtype, objtype), |
|
567 ask_confirm=self.verbosity>=2) |
|
568 if commit: |
|
569 self.commit() |
|
570 |
|
571 def cmd_synchronize_permissions(self, ertype, commit=True): |
|
572 """permission synchronization for an entity or relation type""" |
272 """permission synchronization for an entity or relation type""" |
573 if ertype in ('eid', 'has_text', 'identity'): |
273 if ertype in ('eid', 'has_text', 'identity'): |
574 return |
274 return |
575 newrschema = self.fs_schema[ertype] |
275 newrschema = self.fs_schema[ertype] |
576 teid = self.repo.schema[ertype].eid |
276 teid = self.repo.schema[ertype].eid |
766 # 2. add new constraints |
457 # 2. add new constraints |
767 for newcstr in newconstraints: |
458 for newcstr in newconstraints: |
768 self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype, |
459 self.rqlexecall(ss.constraint2rql(rschema, subjtype, objtype, |
769 newcstr), |
460 newcstr), |
770 ask_confirm=confirm) |
461 ask_confirm=confirm) |
771 if commit: |
462 |
772 self.commit() |
463 # base actions ############################################################ |
773 |
464 |
774 def cmd_synchronize_schema(self, syncperms=True, commit=True): |
465 def checkpoint(self): |
|
466 """checkpoint action""" |
|
467 if self.confirm('commit now ?', shell=False): |
|
468 self.commit() |
|
469 |
|
470 def cmd_add_cube(self, cube, update_database=True): |
|
471 self.cmd_add_cubes( (cube,), update_database) |
|
472 |
|
473 def cmd_add_cubes(self, cubes, update_database=True): |
|
474 """update_database is telling if the database schema should be updated |
|
475 or if only the relevant eproperty should be inserted (for the case where |
|
476 a cube has been extracted from an existing application, so the |
|
477 cube schema is already in there) |
|
478 """ |
|
479 newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes) |
|
480 if not newcubes: |
|
481 return |
|
482 for pack in newcubes: |
|
483 self.cmd_set_property('system.version.'+pack, |
|
484 self.config.cube_version(pack)) |
|
485 if not update_database: |
|
486 self.commit() |
|
487 return |
|
488 newcubes_schema = self.config.load_schema(construction_mode='non-strict') |
|
489 new = set() |
|
490 # execute pre-create files |
|
491 for pack in reversed(newcubes): |
|
492 self.exec_event_script('precreate', self.config.cube_dir(pack)) |
|
493 # add new entity and relation types |
|
494 for rschema in newcubes_schema.relations(): |
|
495 if not rschema in self.repo.schema: |
|
496 self.cmd_add_relation_type(rschema.type) |
|
497 new.add(rschema.type) |
|
498 for eschema in newcubes_schema.entities(): |
|
499 if not eschema in self.repo.schema: |
|
500 self.cmd_add_entity_type(eschema.type) |
|
501 new.add(eschema.type) |
|
502 # check if attributes has been added to existing entities |
|
503 for rschema in newcubes_schema.relations(): |
|
504 existingschema = self.repo.schema.rschema(rschema.type) |
|
505 for (fromtype, totype) in rschema.iter_rdefs(): |
|
506 if existingschema.has_rdef(fromtype, totype): |
|
507 continue |
|
508 # check we should actually add the relation definition |
|
509 if not (fromtype in new or totype in new or rschema in new): |
|
510 continue |
|
511 self.cmd_add_relation_definition(str(fromtype), rschema.type, |
|
512 str(totype)) |
|
513 # execute post-create files |
|
514 for pack in reversed(newcubes): |
|
515 self.exec_event_script('postcreate', self.config.cube_dir(pack)) |
|
516 self.commit() |
|
517 |
|
518 def cmd_remove_cube(self, cube): |
|
519 removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(cube) |
|
520 if not removedcubes: |
|
521 return |
|
522 fsschema = self.fs_schema |
|
523 removedcubes_schema = self.config.load_schema(construction_mode='non-strict') |
|
524 reposchema = self.repo.schema |
|
525 # execute pre-remove files |
|
526 for pack in reversed(removedcubes): |
|
527 self.exec_event_script('preremove', self.config.cube_dir(pack)) |
|
528 # remove cubes'entity and relation types |
|
529 for rschema in fsschema.relations(): |
|
530 if not rschema in removedcubes_schema and rschema in reposchema: |
|
531 self.cmd_drop_relation_type(rschema.type) |
|
532 for eschema in fsschema.entities(): |
|
533 if not eschema in removedcubes_schema and eschema in reposchema: |
|
534 self.cmd_drop_entity_type(eschema.type) |
|
535 for rschema in fsschema.relations(): |
|
536 if rschema in removedcubes_schema and rschema in reposchema: |
|
537 # check if attributes/relations has been added to entities from |
|
538 # other cubes |
|
539 for fromtype, totype in rschema.iter_rdefs(): |
|
540 if not removedcubes_schema[rschema.type].has_rdef(fromtype, totype) and \ |
|
541 reposchema[rschema.type].has_rdef(fromtype, totype): |
|
542 self.cmd_drop_relation_definition( |
|
543 str(fromtype), rschema.type, str(totype)) |
|
544 # execute post-remove files |
|
545 for pack in reversed(removedcubes): |
|
546 self.exec_event_script('postremove', self.config.cube_dir(pack)) |
|
547 self.rqlexec('DELETE CWProperty X WHERE X pkey %(pk)s', |
|
548 {'pk': u'system.version.'+pack}, ask_confirm=False) |
|
549 self.commit() |
|
550 |
|
551 # schema migration actions ################################################ |
|
552 |
|
553 def cmd_add_attribute(self, etype, attrname, attrtype=None, commit=True): |
|
554 """add a new attribute on the given entity type""" |
|
555 if attrtype is None: |
|
556 rschema = self.fs_schema.rschema(attrname) |
|
557 attrtype = rschema.objects(etype)[0] |
|
558 self.cmd_add_relation_definition(etype, attrname, attrtype, commit=commit) |
|
559 |
|
560 def cmd_drop_attribute(self, etype, attrname, commit=True): |
|
561 """drop an existing attribute from the given entity type |
|
562 |
|
563 `attrname` is a string giving the name of the attribute to drop |
|
564 """ |
|
565 rschema = self.repo.schema.rschema(attrname) |
|
566 attrtype = rschema.objects(etype)[0] |
|
567 self.cmd_drop_relation_definition(etype, attrname, attrtype, commit=commit) |
|
568 |
|
569 def cmd_rename_attribute(self, etype, oldname, newname, commit=True): |
|
570 """rename an existing attribute of the given entity type |
|
571 |
|
572 `oldname` is a string giving the name of the existing attribute |
|
573 `newname` is a string giving the name of the renamed attribute |
|
574 """ |
|
575 eschema = self.fs_schema.eschema(etype) |
|
576 attrtype = eschema.destination(newname) |
|
577 # have to commit this first step anyway to get the definition |
|
578 # actually in the schema |
|
579 self.cmd_add_attribute(etype, newname, attrtype, commit=True) |
|
580 # skipp NULL values if the attribute is required |
|
581 rql = 'SET X %s VAL WHERE X is %s, X %s VAL' % (newname, etype, oldname) |
|
582 card = eschema.rproperty(newname, 'cardinality')[0] |
|
583 if card == '1': |
|
584 rql += ', NOT X %s NULL' % oldname |
|
585 self.rqlexec(rql, ask_confirm=self.verbosity>=2) |
|
586 self.cmd_drop_attribute(etype, oldname, commit=commit) |
|
587 |
|
588 def cmd_add_entity_type(self, etype, auto=True, commit=True): |
|
589 """register a new entity type |
|
590 |
|
591 in auto mode, automatically register entity's relation where the |
|
592 targeted type is known |
|
593 """ |
|
594 applschema = self.repo.schema |
|
595 if etype in applschema: |
|
596 eschema = applschema[etype] |
|
597 if eschema.is_final(): |
|
598 applschema.del_entity_type(etype) |
|
599 else: |
|
600 eschema = self.fs_schema.eschema(etype) |
|
601 confirm = self.verbosity >= 2 |
|
602 # register the entity into CWEType |
|
603 self.rqlexecall(ss.eschema2rql(eschema), ask_confirm=confirm) |
|
604 # add specializes relation if needed |
|
605 self.rqlexecall(ss.eschemaspecialize2rql(eschema), ask_confirm=confirm) |
|
606 # register groups / permissions for the entity |
|
607 self.rqlexecall(ss.erperms2rql(eschema, self.group_mapping()), |
|
608 ask_confirm=confirm) |
|
609 # register entity's attributes |
|
610 for rschema, attrschema in eschema.attribute_definitions(): |
|
611 # ignore those meta relations, they will be automatically added |
|
612 if rschema.type in ('eid', 'creation_date', 'modification_date'): |
|
613 continue |
|
614 if not rschema.type in applschema: |
|
615 # need to add the relation type and to commit to get it |
|
616 # actually in the schema |
|
617 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
618 # register relation definition |
|
619 self.rqlexecall(ss.rdef2rql(rschema, etype, attrschema.type), |
|
620 ask_confirm=confirm) |
|
621 if auto: |
|
622 # we have commit here to get relation types actually in the schema |
|
623 self.commit() |
|
624 added = [] |
|
625 for rschema in eschema.subject_relations(): |
|
626 # attribute relation have already been processed and |
|
627 # 'owned_by'/'created_by' will be automatically added |
|
628 if rschema.final or rschema.type in ('owned_by', 'created_by', 'is', 'is_instance_of'): |
|
629 continue |
|
630 rtypeadded = rschema.type in applschema |
|
631 for targetschema in rschema.objects(etype): |
|
632 # ignore relations where the targeted type is not in the |
|
633 # current application schema |
|
634 targettype = targetschema.type |
|
635 if not targettype in applschema and targettype != etype: |
|
636 continue |
|
637 if not rtypeadded: |
|
638 # need to add the relation type and to commit to get it |
|
639 # actually in the schema |
|
640 added.append(rschema.type) |
|
641 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
642 rtypeadded = True |
|
643 # register relation definition |
|
644 # remember this two avoid adding twice non symetric relation |
|
645 # such as "Emailthread forked_from Emailthread" |
|
646 added.append((etype, rschema.type, targettype)) |
|
647 self.rqlexecall(ss.rdef2rql(rschema, etype, targettype), |
|
648 ask_confirm=confirm) |
|
649 for rschema in eschema.object_relations(): |
|
650 rtypeadded = rschema.type in applschema or rschema.type in added |
|
651 for targetschema in rschema.subjects(etype): |
|
652 # ignore relations where the targeted type is not in the |
|
653 # current application schema |
|
654 targettype = targetschema.type |
|
655 # don't check targettype != etype since in this case the |
|
656 # relation has already been added as a subject relation |
|
657 if not targettype in applschema: |
|
658 continue |
|
659 if not rtypeadded: |
|
660 # need to add the relation type and to commit to get it |
|
661 # actually in the schema |
|
662 self.cmd_add_relation_type(rschema.type, False, commit=True) |
|
663 rtypeadded = True |
|
664 elif (targettype, rschema.type, etype) in added: |
|
665 continue |
|
666 # register relation definition |
|
667 self.rqlexecall(ss.rdef2rql(rschema, targettype, etype), |
|
668 ask_confirm=confirm) |
|
669 if commit: |
|
670 self.commit() |
|
671 |
|
672 def cmd_drop_entity_type(self, etype, commit=True): |
|
673 """unregister an existing entity type |
|
674 |
|
675 This will trigger deletion of necessary relation types and definitions |
|
676 """ |
|
677 # XXX what if we delete an entity type which is specialized by other types |
|
678 # unregister the entity from CWEType |
|
679 self.rqlexec('DELETE CWEType X WHERE X name %(etype)s', {'etype': etype}, |
|
680 ask_confirm=self.verbosity>=2) |
|
681 if commit: |
|
682 self.commit() |
|
683 |
|
684 def cmd_rename_entity_type(self, oldname, newname, commit=True): |
|
685 """rename an existing entity type in the persistent schema |
|
686 |
|
687 `oldname` is a string giving the name of the existing entity type |
|
688 `newname` is a string giving the name of the renamed entity type |
|
689 """ |
|
690 self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(oldname)s', |
|
691 {'newname' : unicode(newname), 'oldname' : oldname}) |
|
692 if commit: |
|
693 self.commit() |
|
694 |
|
695 def cmd_add_relation_type(self, rtype, addrdef=True, commit=True): |
|
696 """register a new relation type named `rtype`, as described in the |
|
697 schema description file. |
|
698 |
|
699 `addrdef` is a boolean value; when True, it will also add all relations |
|
700 of the type just added found in the schema definition file. Note that it |
|
701 implies an intermediate "commit" which commits the relation type |
|
702 creation (but not the relation definitions themselves, for which |
|
703 committing depends on the `commit` argument value). |
|
704 |
|
705 """ |
|
706 rschema = self.fs_schema.rschema(rtype) |
|
707 # register the relation into CWRType and insert necessary relation |
|
708 # definitions |
|
709 self.rqlexecall(ss.rschema2rql(rschema, addrdef=False), |
|
710 ask_confirm=self.verbosity>=2) |
|
711 # register groups / permissions for the relation |
|
712 self.rqlexecall(ss.erperms2rql(rschema, self.group_mapping()), |
|
713 ask_confirm=self.verbosity>=2) |
|
714 if addrdef: |
|
715 self.commit() |
|
716 self.rqlexecall(ss.rdef2rql(rschema), |
|
717 ask_confirm=self.verbosity>=2) |
|
718 if commit: |
|
719 self.commit() |
|
720 |
|
721 def cmd_drop_relation_type(self, rtype, commit=True): |
|
722 """unregister an existing relation type""" |
|
723 # unregister the relation from CWRType |
|
724 self.rqlexec('DELETE CWRType X WHERE X name %r' % rtype, |
|
725 ask_confirm=self.verbosity>=2) |
|
726 if commit: |
|
727 self.commit() |
|
728 |
|
729 def cmd_rename_relation(self, oldname, newname, commit=True): |
|
730 """rename an existing relation |
|
731 |
|
732 `oldname` is a string giving the name of the existing relation |
|
733 `newname` is a string giving the name of the renamed relation |
|
734 """ |
|
735 self.cmd_add_relation_type(newname, commit=True) |
|
736 self.rqlexec('SET X %s Y WHERE X %s Y' % (newname, oldname), |
|
737 ask_confirm=self.verbosity>=2) |
|
738 self.cmd_drop_relation_type(oldname, commit=commit) |
|
739 |
|
740 def cmd_add_relation_definition(self, subjtype, rtype, objtype, commit=True): |
|
741 """register a new relation definition, from its definition found in the |
|
742 schema definition file |
|
743 """ |
|
744 rschema = self.fs_schema.rschema(rtype) |
|
745 if not rtype in self.repo.schema: |
|
746 self.cmd_add_relation_type(rtype, addrdef=False, commit=True) |
|
747 self.rqlexecall(ss.rdef2rql(rschema, subjtype, objtype), |
|
748 ask_confirm=self.verbosity>=2) |
|
749 if commit: |
|
750 self.commit() |
|
751 |
|
752 def cmd_drop_relation_definition(self, subjtype, rtype, objtype, commit=True): |
|
753 """unregister an existing relation definition""" |
|
754 rschema = self.repo.schema.rschema(rtype) |
|
755 # unregister the definition from CWAttribute or CWRelation |
|
756 if rschema.is_final(): |
|
757 etype = 'CWAttribute' |
|
758 else: |
|
759 etype = 'CWRelation' |
|
760 rql = ('DELETE %s X WHERE X from_entity FE, FE name "%s",' |
|
761 'X relation_type RT, RT name "%s", X to_entity TE, TE name "%s"') |
|
762 self.rqlexec(rql % (etype, subjtype, rtype, objtype), |
|
763 ask_confirm=self.verbosity>=2) |
|
764 if commit: |
|
765 self.commit() |
|
766 |
|
767 def cmd_sync_schema_props_perms(self, ertype=None, syncperms=True, |
|
768 syncprops=True, syncrdefs=True, commit=True) |
775 """synchronize the persistent schema against the current definition |
769 """synchronize the persistent schema against the current definition |
776 schema. |
770 schema. |
777 |
771 |
778 It will synch common stuff between the definition schema and the |
772 It will synch common stuff between the definition schema and the |
779 actual persistent schema, it won't add/remove any entity or relation. |
773 actual persistent schema, it won't add/remove any entity or relation. |
780 """ |
774 """ |
781 for etype in self.repo.schema.entities(): |
775 assert syncperms or syncprops, 'nothing to do' |
782 self.cmd_synchronize_eschema(etype, syncperms=syncperms, commit=False) |
776 if ertype is not None: |
|
777 if isinstance(ertype, (tuple, list)): |
|
778 assert len(ertype) == 3, 'not a relation definition' |
|
779 assert syncprops, 'can\'t update permission for a relation definition' |
|
780 self._synchronize_rdef_schema(*ertype) |
|
781 elif syncprops: |
|
782 erschema = self.repo.schema[ertype] |
|
783 if isinstance(erschema, CubicWebRelationSchema): |
|
784 self._synchronize_rschema(erschema, syncperms=syncperms, |
|
785 syncrdefs=syncrdefs) |
|
786 else: |
|
787 self._synchronize_eschema(erschema, syncperms=syncperms) |
|
788 else: |
|
789 self._synchronize_permissions(ertype) |
|
790 else: |
|
791 for etype in self.repo.schema.entities(): |
|
792 if syncprops: |
|
793 self._synchronize_eschema(etype, syncperms=syncperms) |
|
794 else: |
|
795 self._synchronize_permissions(etype) |
783 if commit: |
796 if commit: |
784 self.commit() |
797 self.commit() |
785 |
798 |
786 def cmd_change_relation_props(self, subjtype, rtype, objtype, |
799 def cmd_change_relation_props(self, subjtype, rtype, objtype, |
787 commit=True, **kwargs): |
800 commit=True, **kwargs): |
788 """change some properties of a relation definition""" |
801 """change some properties of a relation definition |
|
802 |
|
803 you usually want to use sync_schema_props_perms instead. |
|
804 """ |
789 assert kwargs |
805 assert kwargs |
790 restriction = [] |
806 restriction = [] |
791 if subjtype and subjtype != 'Any': |
807 if subjtype and subjtype != 'Any': |
792 restriction.append('X from_entity FE, FE name "%s"' % subjtype) |
808 restriction.append('X from_entity FE, FE name "%s"' % subjtype) |
793 if objtype and objtype != 'Any': |
809 if objtype and objtype != 'Any': |