43 from cubicweb.server.sqlutils import SQL_PREFIX |
43 from cubicweb.server.sqlutils import SQL_PREFIX |
44 from cubicweb.hooks.synccomputed import RecomputeAttributeOperation |
44 from cubicweb.hooks.synccomputed import RecomputeAttributeOperation |
45 |
45 |
46 # core entity and relation types which can't be removed |
46 # core entity and relation types which can't be removed |
47 CORE_TYPES = BASE_TYPES | SCHEMA_TYPES | META_RTYPES | set( |
47 CORE_TYPES = BASE_TYPES | SCHEMA_TYPES | META_RTYPES | set( |
48 ('CWUser', 'CWGroup','login', 'upassword', 'name', 'in_group')) |
48 ('CWUser', 'CWGroup', 'login', 'upassword', 'name', 'in_group')) |
49 |
49 |
50 |
50 |
51 def get_constraints(cnx, entity): |
51 def get_constraints(cnx, entity): |
52 constraints = [] |
52 constraints = [] |
53 for cstreid in cnx.transaction_data.get(entity.eid, ()): |
53 for cstreid in cnx.transaction_data.get(entity.eid, ()): |
74 return |
74 return |
75 createdattrs.add(attrkey) |
75 createdattrs.add(attrkey) |
76 table = SQL_PREFIX + etype |
76 table = SQL_PREFIX + etype |
77 column = SQL_PREFIX + rtype |
77 column = SQL_PREFIX + rtype |
78 try: |
78 try: |
79 cnx.system_sql(str('ALTER TABLE %s ADD %s integer REFERENCES entities (eid)' % (table, column)), |
79 cnx.system_sql(str('ALTER TABLE %s ADD %s integer REFERENCES entities (eid)' |
|
80 % (table, column)), |
80 rollback_on_failure=False) |
81 rollback_on_failure=False) |
81 cnx.info('added column %s to table %s', column, table) |
82 cnx.info('added column %s to table %s', column, table) |
82 except Exception: |
83 except Exception: |
83 # silent exception here, if this error has not been raised because the |
84 # silent exception here, if this error has not been raised because the |
84 # column already exists, index creation will fail anyway |
85 # column already exists, index creation will fail anyway |
238 * create the necessary table |
239 * create the necessary table |
239 * set creation_date and modification_date by creating the necessary |
240 * set creation_date and modification_date by creating the necessary |
240 CWAttribute entities |
241 CWAttribute entities |
241 * add <meta rtype> relation by creating the necessary CWRelation entity |
242 * add <meta rtype> relation by creating the necessary CWRelation entity |
242 """ |
243 """ |
243 entity = None # make pylint happy |
244 entity = None # make pylint happy |
244 |
245 |
245 def precommit_event(self): |
246 def precommit_event(self): |
246 cnx = self.cnx |
247 cnx = self.cnx |
247 entity = self.entity |
248 entity = self.entity |
248 schema = cnx.vreg.schema |
249 schema = cnx.vreg.schema |
358 op.add_data(objtype) |
359 op.add_data(objtype) |
359 else: |
360 else: |
360 op.add_data(objtype) |
361 op.add_data(objtype) |
361 op.add_data(subjtype) |
362 op.add_data(subjtype) |
362 # update the in-memory schema first |
363 # update the in-memory schema first |
363 self.oldvalues = dict( (attr, getattr(rschema, attr)) for attr in self.values) |
364 self.oldvalues = dict((attr, getattr(rschema, attr)) for attr in self.values) |
364 self.rschema.__dict__.update(self.values) |
365 self.rschema.__dict__.update(self.values) |
365 # then make necessary changes to the system source database |
366 # then make necessary changes to the system source database |
366 if 'inlined' not in self.values: |
367 if 'inlined' not in self.values: |
367 return # nothing to do |
368 return # nothing to do |
368 inlined = self.values['inlined'] |
369 inlined = self.values['inlined'] |
369 # check in-lining is possible when inlined |
370 # check in-lining is possible when inlined |
370 if inlined: |
371 if inlined: |
371 self.entity.check_inlined_allowed() |
372 self.entity.check_inlined_allowed() |
372 # inlined changed, make necessary physical changes! |
373 # inlined changed, make necessary physical changes! |
374 rtype = rschema.type |
375 rtype = rschema.type |
375 eidcolumn = SQL_PREFIX + 'eid' |
376 eidcolumn = SQL_PREFIX + 'eid' |
376 if not inlined: |
377 if not inlined: |
377 # need to create the relation if it has not been already done by |
378 # need to create the relation if it has not been already done by |
378 # another event of the same transaction |
379 # another event of the same transaction |
379 if not rschema.type in cnx.transaction_data.get('createdtables', ()): |
380 if rschema.type not in cnx.transaction_data.get('createdtables', ()): |
380 # create the necessary table |
381 # create the necessary table |
381 for sql in y2sql.rschema2sql(rschema): |
382 for sql in y2sql.rschema2sql(rschema): |
382 sqlexec(sql) |
383 sqlexec(sql) |
383 cnx.transaction_data.setdefault('createdtables', []).append( |
384 cnx.transaction_data.setdefault('createdtables', []).append( |
384 rschema.type) |
385 rschema.type) |
387 for etype in rschema.subjects(): |
388 for etype in rschema.subjects(): |
388 table = SQL_PREFIX + str(etype) |
389 table = SQL_PREFIX + str(etype) |
389 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
390 sqlexec('INSERT INTO %s_relation SELECT %s, %s FROM %s WHERE NOT %s IS NULL' |
390 % (rtype, eidcolumn, column, table, column)) |
391 % (rtype, eidcolumn, column, table, column)) |
391 # drop existant columns |
392 # drop existant columns |
392 #if cnx.repo.system_source.dbhelper.alter_column_support: |
|
393 for etype in rschema.subjects(): |
393 for etype in rschema.subjects(): |
394 DropColumn.get_instance(cnx).add_data((str(etype), rtype)) |
394 DropColumn.get_instance(cnx).add_data((str(etype), rtype)) |
395 else: |
395 else: |
396 for etype in rschema.subjects(): |
396 for etype in rschema.subjects(): |
397 try: |
397 try: |
425 # XXX revert changes on database |
425 # XXX revert changes on database |
426 |
426 |
427 |
427 |
428 class CWComputedRTypeUpdateOp(MemSchemaOperation): |
428 class CWComputedRTypeUpdateOp(MemSchemaOperation): |
429 """actually update some properties of a computed relation definition""" |
429 """actually update some properties of a computed relation definition""" |
430 rschema = entity = rule = None # make pylint happy |
430 rschema = entity = rule = None # make pylint happy |
431 old_rule = None |
431 old_rule = None |
432 |
432 |
433 def precommit_event(self): |
433 def precommit_event(self): |
434 # update the in-memory schema first |
434 # update the in-memory schema first |
435 self.old_rule = self.rschema.rule |
435 self.old_rule = self.rschema.rule |
447 * register an operation to add the relation definition to the |
447 * register an operation to add the relation definition to the |
448 instance's schema on commit |
448 instance's schema on commit |
449 |
449 |
450 constraints are handled by specific hooks |
450 constraints are handled by specific hooks |
451 """ |
451 """ |
452 entity = None # make pylint happy |
452 entity = None # make pylint happy |
453 |
453 |
454 def init_rdef(self, **kwargs): |
454 def init_rdef(self, **kwargs): |
455 entity = self.entity |
455 entity = self.entity |
456 fromentity = entity.stype |
456 fromentity = entity.stype |
457 rdefdef = self.rdefdef = ybo.RelationDefinition( |
457 rdefdef = self.rdefdef = ybo.RelationDefinition( |
522 # final relations are not infered, propagate |
522 # final relations are not infered, propagate |
523 schema = cnx.vreg.schema |
523 schema = cnx.vreg.schema |
524 try: |
524 try: |
525 eschema = schema.eschema(rdefdef.subject) |
525 eschema = schema.eschema(rdefdef.subject) |
526 except KeyError: |
526 except KeyError: |
527 return # entity type currently being added |
527 return # entity type currently being added |
528 # propagate attribute to children classes |
528 # propagate attribute to children classes |
529 rschema = schema.rschema(rdefdef.name) |
529 rschema = schema.rschema(rdefdef.name) |
530 # if relation type has been inserted in the same transaction, its final |
530 # if relation type has been inserted in the same transaction, its final |
531 # attribute is still set to False, so we've to ensure it's False |
531 # attribute is still set to False, so we've to ensure it's False |
532 rschema.final = True |
532 rschema.final = True |
533 insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props) |
533 insert_rdef_on_subclasses(cnx, eschema, rschema, rdefdef, props) |
534 # update existing entities with the default value of newly added attribute |
534 # update existing entities with the default value of newly added attribute |
535 if default is not None: |
535 if default is not None: |
536 default = convert_default_value(self.rdefdef, default) |
536 default = convert_default_value(self.rdefdef, default) |
537 cnx.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
537 cnx.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
538 {'default': default}) |
538 {'default': default}) |
539 # if attribute is computed, compute it |
539 # if attribute is computed, compute it |
540 if getattr(entity, 'formula', None): |
540 if getattr(entity, 'formula', None): |
541 # add rtype attribute for RelationDefinitionSchema api compat, this |
541 # add rtype attribute for RelationDefinitionSchema api compat, this |
542 # is what RecomputeAttributeOperation expect |
542 # is what RecomputeAttributeOperation expect |
543 rdefdef.rtype = rdefdef.name |
543 rdefdef.rtype = rdefdef.name |
561 first instance of this relation type, add the necessary table and set |
561 first instance of this relation type, add the necessary table and set |
562 default permissions |
562 default permissions |
563 |
563 |
564 constraints are handled by specific hooks |
564 constraints are handled by specific hooks |
565 """ |
565 """ |
566 entity = None # make pylint happy |
566 entity = None # make pylint happy |
567 |
567 |
568 def precommit_event(self): |
568 def precommit_event(self): |
569 cnx = self.cnx |
569 cnx = self.cnx |
570 entity = self.entity |
570 entity = self.entity |
571 # update the in-memory schema first |
571 # update the in-memory schema first |
668 self.cnx.vreg.schema.add_relation_def(rdef) |
668 self.cnx.vreg.schema.add_relation_def(rdef) |
669 |
669 |
670 |
670 |
671 class RDefUpdateOp(MemSchemaOperation): |
671 class RDefUpdateOp(MemSchemaOperation): |
672 """actually update some properties of a relation definition""" |
672 """actually update some properties of a relation definition""" |
673 rschema = rdefkey = values = None # make pylint happy |
673 rschema = rdefkey = values = None # make pylint happy |
674 rdef = oldvalues = None |
674 rdef = oldvalues = None |
675 indexed_changed = null_allowed_changed = False |
675 indexed_changed = null_allowed_changed = False |
676 |
676 |
677 def precommit_event(self): |
677 def precommit_event(self): |
678 cnx = self.cnx |
678 cnx = self.cnx |
679 rdef = self.rdef = self.rschema.rdefs[self.rdefkey] |
679 rdef = self.rdef = self.rschema.rdefs[self.rdefkey] |
680 # update the in-memory schema first |
680 # update the in-memory schema first |
681 self.oldvalues = dict( (attr, getattr(rdef, attr)) for attr in self.values) |
681 self.oldvalues = dict((attr, getattr(rdef, attr)) for attr in self.values) |
682 rdef.update(self.values) |
682 rdef.update(self.values) |
683 # then make necessary changes to the system source database |
683 # then make necessary changes to the system source database |
684 syssource = cnx.repo.system_source |
684 syssource = cnx.repo.system_source |
685 if 'indexed' in self.values: |
685 if 'indexed' in self.values: |
686 syssource.update_rdef_indexed(cnx, rdef) |
686 syssource.update_rdef_indexed(cnx, rdef) |
687 self.indexed_changed = True |
687 self.indexed_changed = True |
688 if 'cardinality' in self.values and rdef.rtype.final \ |
688 if ('cardinality' in self.values and rdef.rtype.final |
689 and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]: |
689 and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]): |
690 syssource.update_rdef_null_allowed(self.cnx, rdef) |
690 syssource.update_rdef_null_allowed(self.cnx, rdef) |
691 self.null_allowed_changed = True |
691 self.null_allowed_changed = True |
692 if 'fulltextindexed' in self.values: |
692 if 'fulltextindexed' in self.values: |
693 UpdateFTIndexOp.get_instance(cnx).add_data(rdef.subject) |
693 UpdateFTIndexOp.get_instance(cnx).add_data(rdef.subject) |
694 if 'formula' in self.values: |
694 if 'formula' in self.values: |
715 rdef.constraints = list(rdef.constraints) |
715 rdef.constraints = list(rdef.constraints) |
716 |
716 |
717 |
717 |
718 class CWConstraintDelOp(MemSchemaOperation): |
718 class CWConstraintDelOp(MemSchemaOperation): |
719 """actually remove a constraint of a relation definition""" |
719 """actually remove a constraint of a relation definition""" |
720 rdef = oldcstr = newcstr = None # make pylint happy |
720 rdef = oldcstr = newcstr = None # make pylint happy |
721 size_cstr_changed = unique_changed = False |
721 size_cstr_changed = unique_changed = False |
722 |
722 |
723 def precommit_event(self): |
723 def precommit_event(self): |
724 cnx = self.cnx |
724 cnx = self.cnx |
725 rdef = self.rdef |
725 rdef = self.rdef |
773 syssource.update_rdef_unique(self.cnx, self.rdef) |
773 syssource.update_rdef_unique(self.cnx, self.rdef) |
774 |
774 |
775 |
775 |
776 class CWConstraintAddOp(CWConstraintDelOp): |
776 class CWConstraintAddOp(CWConstraintDelOp): |
777 """actually update constraint of a relation definition""" |
777 """actually update constraint of a relation definition""" |
778 entity = None # make pylint happy |
778 entity = None # make pylint happy |
779 |
779 |
780 def precommit_event(self): |
780 def precommit_event(self): |
781 cnx = self.cnx |
781 cnx = self.cnx |
782 rdefentity = self.entity.reverse_constrained_by[0] |
782 rdefentity = self.entity.reverse_constrained_by[0] |
783 rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid) |
783 rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid) |
818 cnx.system_sql('ALTER TABLE %s%s ADD CONSTRAINT %s CHECK(%s)' % |
818 cnx.system_sql('ALTER TABLE %s%s ADD CONSTRAINT %s CHECK(%s)' % |
819 (SQL_PREFIX, rdef.subject, cstrname, check)) |
819 (SQL_PREFIX, rdef.subject, cstrname, check)) |
820 |
820 |
821 |
821 |
822 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation): |
822 class CWUniqueTogetherConstraintAddOp(MemSchemaOperation): |
823 entity = None # make pylint happy |
823 entity = None # make pylint happy |
824 |
824 |
825 def precommit_event(self): |
825 def precommit_event(self): |
826 cnx = self.cnx |
826 cnx = self.cnx |
827 prefix = SQL_PREFIX |
827 prefix = SQL_PREFIX |
828 entity = self.entity |
828 entity = self.entity |
839 attrs = [r.name for r in entity.relations] |
839 attrs = [r.name for r in entity.relations] |
840 eschema._unique_together.append(attrs) |
840 eschema._unique_together.append(attrs) |
841 |
841 |
842 |
842 |
843 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation): |
843 class CWUniqueTogetherConstraintDelOp(MemSchemaOperation): |
844 entity = cstrname = None # for pylint |
844 entity = cstrname = None # make pylint happy |
845 cols = () # for pylint |
845 cols = () # make pylint happy |
846 |
846 |
847 def insert_index(self): |
847 def insert_index(self): |
848 # We need to run before CWConstraintDelOp: if a size constraint is |
848 # We need to run before CWConstraintDelOp: if a size constraint is |
849 # removed and the column is part of a unique_together constraint, we |
849 # removed and the column is part of a unique_together constraint, we |
850 # remove the unique_together index before changing the column's type. |
850 # remove the unique_together index before changing the column's type. |
871 |
871 |
872 # operations for in-memory schema synchronization ############################# |
872 # operations for in-memory schema synchronization ############################# |
873 |
873 |
874 class MemSchemaCWETypeDel(MemSchemaOperation): |
874 class MemSchemaCWETypeDel(MemSchemaOperation): |
875 """actually remove the entity type from the instance's schema""" |
875 """actually remove the entity type from the instance's schema""" |
876 etype = None # make pylint happy |
876 etype = None # make pylint happy |
877 |
877 |
878 def postcommit_event(self): |
878 def postcommit_event(self): |
879 # del_entity_type also removes entity's relations |
879 # del_entity_type also removes entity's relations |
880 self.cnx.vreg.schema.del_entity_type(self.etype) |
880 self.cnx.vreg.schema.del_entity_type(self.etype) |
881 |
881 |
882 |
882 |
883 class MemSchemaCWRTypeAdd(MemSchemaOperation): |
883 class MemSchemaCWRTypeAdd(MemSchemaOperation): |
884 """actually add the relation type to the instance's schema""" |
884 """actually add the relation type to the instance's schema""" |
885 rtypedef = None # make pylint happy |
885 rtypedef = None # make pylint happy |
886 |
886 |
887 def precommit_event(self): |
887 def precommit_event(self): |
888 self.cnx.vreg.schema.add_relation_type(self.rtypedef) |
888 self.cnx.vreg.schema.add_relation_type(self.rtypedef) |
889 |
889 |
890 def revertprecommit_event(self): |
890 def revertprecommit_event(self): |
891 self.cnx.vreg.schema.del_relation_type(self.rtypedef.name) |
891 self.cnx.vreg.schema.del_relation_type(self.rtypedef.name) |
892 |
892 |
893 |
893 |
894 class MemSchemaCWRTypeDel(MemSchemaOperation): |
894 class MemSchemaCWRTypeDel(MemSchemaOperation): |
895 """actually remove the relation type from the instance's schema""" |
895 """actually remove the relation type from the instance's schema""" |
896 rtype = None # make pylint happy |
896 rtype = None # make pylint happy |
897 |
897 |
898 def postcommit_event(self): |
898 def postcommit_event(self): |
899 try: |
899 try: |
900 self.cnx.vreg.schema.del_relation_type(self.rtype) |
900 self.cnx.vreg.schema.del_relation_type(self.rtype) |
901 except KeyError: |
901 except KeyError: |
904 |
904 |
905 |
905 |
906 class MemSchemaPermissionAdd(MemSchemaOperation): |
906 class MemSchemaPermissionAdd(MemSchemaOperation): |
907 """synchronize schema when a *_permission relation has been added on a group |
907 """synchronize schema when a *_permission relation has been added on a group |
908 """ |
908 """ |
909 eid = action = group_eid = expr = None # make pylint happy |
909 eid = action = group_eid = expr = None # make pylint happy |
910 |
910 |
911 def precommit_event(self): |
911 def precommit_event(self): |
912 """the observed connections.cnxset has been commited""" |
912 """the observed connections.cnxset has been commited""" |
913 try: |
913 try: |
914 erschema = self.cnx.vreg.schema.schema_by_eid(self.eid) |
914 erschema = self.cnx.vreg.schema.schema_by_eid(self.eid) |
959 |
959 |
960 # XXX revertprecommit_event |
960 # XXX revertprecommit_event |
961 |
961 |
962 |
962 |
963 class MemSchemaSpecializesAdd(MemSchemaOperation): |
963 class MemSchemaSpecializesAdd(MemSchemaOperation): |
964 etypeeid = parentetypeeid = None # make pylint happy |
964 etypeeid = parentetypeeid = None # make pylint happy |
965 |
965 |
966 def precommit_event(self): |
966 def precommit_event(self): |
967 eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid) |
967 eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid) |
968 parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid) |
968 parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid) |
969 eschema._specialized_type = parenteschema.type |
969 eschema._specialized_type = parenteschema.type |
971 |
971 |
972 # XXX revertprecommit_event |
972 # XXX revertprecommit_event |
973 |
973 |
974 |
974 |
975 class MemSchemaSpecializesDel(MemSchemaOperation): |
975 class MemSchemaSpecializesDel(MemSchemaOperation): |
976 etypeeid = parentetypeeid = None # make pylint happy |
976 etypeeid = parentetypeeid = None # make pylint happy |
977 |
977 |
978 def precommit_event(self): |
978 def precommit_event(self): |
979 try: |
979 try: |
980 eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid) |
980 eschema = self.cnx.vreg.schema.schema_by_eid(self.etypeeid) |
981 parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid) |
981 parenteschema = self.cnx.vreg.schema.schema_by_eid(self.parentetypeeid) |
1075 name = self.entity.name |
1075 name = self.entity.name |
1076 if name in CORE_TYPES: |
1076 if name in CORE_TYPES: |
1077 raise validation_error(self.entity, {None: _("can't be deleted")}) |
1077 raise validation_error(self.entity, {None: _("can't be deleted")}) |
1078 # delete relation definitions using this relation type |
1078 # delete relation definitions using this relation type |
1079 self._cw.execute('DELETE CWAttribute X WHERE X relation_type Y, Y eid %(x)s', |
1079 self._cw.execute('DELETE CWAttribute X WHERE X relation_type Y, Y eid %(x)s', |
1080 {'x': self.entity.eid}) |
1080 {'x': self.entity.eid}) |
1081 self._cw.execute('DELETE CWRelation X WHERE X relation_type Y, Y eid %(x)s', |
1081 self._cw.execute('DELETE CWRelation X WHERE X relation_type Y, Y eid %(x)s', |
1082 {'x': self.entity.eid}) |
1082 {'x': self.entity.eid}) |
1083 MemSchemaCWRTypeDel(self._cw, rtype=name) |
1083 MemSchemaCWRTypeDel(self._cw, rtype=name) |
1084 |
1084 |
1085 |
1085 |
1086 class AfterAddCWComputedRTypeHook(SyncSchemaHook): |
1086 class AfterAddCWComputedRTypeHook(SyncSchemaHook): |
1087 """after a CWComputedRType entity has been added: |
1087 """after a CWComputedRType entity has been added: |
1183 return |
1183 return |
1184 subjschema, rschema, objschema = rdef.as_triple() |
1184 subjschema, rschema, objschema = rdef.as_triple() |
1185 pendingrdefs = cnx.transaction_data.setdefault('pendingrdefs', set()) |
1185 pendingrdefs = cnx.transaction_data.setdefault('pendingrdefs', set()) |
1186 # first delete existing relation if necessary |
1186 # first delete existing relation if necessary |
1187 if rschema.final: |
1187 if rschema.final: |
1188 rdeftype = 'CWAttribute' |
|
1189 pendingrdefs.add((subjschema, rschema)) |
1188 pendingrdefs.add((subjschema, rschema)) |
1190 else: |
1189 else: |
1191 rdeftype = 'CWRelation' |
|
1192 pendingrdefs.add((subjschema, rschema, objschema)) |
1190 pendingrdefs.add((subjschema, rschema, objschema)) |
1193 RDefDelOp(cnx, rdef=rdef) |
1191 RDefDelOp(cnx, rdef=rdef) |
1194 |
1192 |
1195 |
1193 |
1196 # CWComputedRType hooks ####################################################### |
1194 # CWComputedRType hooks ####################################################### |
1307 except (KeyError, IndexError): |
1305 except (KeyError, IndexError): |
1308 self._cw.critical('constraint type no more accessible') |
1306 self._cw.critical('constraint type no more accessible') |
1309 else: |
1307 else: |
1310 CWConstraintDelOp(self._cw, rdef=rdef, oldcstr=cstr) |
1308 CWConstraintDelOp(self._cw, rdef=rdef, oldcstr=cstr) |
1311 |
1309 |
|
1310 |
1312 # unique_together constraints |
1311 # unique_together constraints |
1313 # XXX: use setoperations and before_add_relation here (on constraint_of and relations) |
1312 # XXX: use setoperations and before_add_relation here (on constraint_of and relations) |
1314 class AfterAddCWUniqueTogetherConstraintHook(SyncSchemaHook): |
1313 class AfterAddCWUniqueTogetherConstraintHook(SyncSchemaHook): |
1315 __regid__ = 'syncadd_cwuniquetogether_constraint' |
1314 __regid__ = 'syncadd_cwuniquetogether_constraint' |
1316 __select__ = SyncSchemaHook.__select__ & is_instance('CWUniqueTogetherConstraint') |
1315 __select__ = SyncSchemaHook.__select__ & is_instance('CWUniqueTogetherConstraint') |
1349 def __call__(self): |
1348 def __call__(self): |
1350 action = self.rtype.split('_', 1)[0] |
1349 action = self.rtype.split('_', 1)[0] |
1351 if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup': |
1350 if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup': |
1352 MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom, |
1351 MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom, |
1353 group_eid=self.eidto) |
1352 group_eid=self.eidto) |
1354 else: # RQLExpression |
1353 else: # RQLExpression |
1355 expr = self._cw.entity_from_eid(self.eidto).expression |
1354 expr = self._cw.entity_from_eid(self.eidto).expression |
1356 MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom, |
1355 MemSchemaPermissionAdd(self._cw, action=action, eid=self.eidfrom, |
1357 expr=expr) |
1356 expr=expr) |
1358 |
1357 |
1359 |
1358 |
1370 return |
1369 return |
1371 action = self.rtype.split('_', 1)[0] |
1370 action = self.rtype.split('_', 1)[0] |
1372 if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup': |
1371 if self._cw.entity_metas(self.eidto)['type'] == 'CWGroup': |
1373 MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom, |
1372 MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom, |
1374 group_eid=self.eidto) |
1373 group_eid=self.eidto) |
1375 else: # RQLExpression |
1374 else: # RQLExpression |
1376 expr = self._cw.entity_from_eid(self.eidto).expression |
1375 expr = self._cw.entity_from_eid(self.eidto).expression |
1377 MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom, |
1376 MemSchemaPermissionDel(self._cw, action=action, eid=self.eidfrom, |
1378 expr=expr) |
1377 expr=expr) |
1379 |
|
1380 |
1378 |
1381 |
1379 |
1382 class UpdateFTIndexOp(hook.DataOperationMixIn, hook.SingleLastOperation): |
1380 class UpdateFTIndexOp(hook.DataOperationMixIn, hook.SingleLastOperation): |
1383 """operation to update full text indexation of entity whose schema change |
1381 """operation to update full text indexation of entity whose schema change |
1384 |
1382 |
1408 if to_reindex: |
1406 if to_reindex: |
1409 # Transaction has already been committed |
1407 # Transaction has already been committed |
1410 cnx.cnxset.commit() |
1408 cnx.cnxset.commit() |
1411 |
1409 |
1412 |
1410 |
1413 |
|
1414 |
|
1415 # specializes synchronization hooks ############################################ |
1411 # specializes synchronization hooks ############################################ |
1416 |
|
1417 |
1412 |
1418 class AfterAddSpecializesHook(SyncSchemaHook): |
1413 class AfterAddSpecializesHook(SyncSchemaHook): |
1419 __regid__ = 'syncaddspecializes' |
1414 __regid__ = 'syncaddspecializes' |
1420 __select__ = SyncSchemaHook.__select__ & hook.match_rtype('specializes') |
1415 __select__ = SyncSchemaHook.__select__ & hook.match_rtype('specializes') |
1421 events = ('after_add_relation',) |
1416 events = ('after_add_relation',) |