21 from cubicweb.server.pool import Operation, SingleLastOperation, PreCommitOperation |
21 from cubicweb.server.pool import Operation, SingleLastOperation, PreCommitOperation |
22 from cubicweb.server.hookhelper import (entity_attr, entity_name, |
22 from cubicweb.server.hookhelper import (entity_attr, entity_name, |
23 check_internal_entity) |
23 check_internal_entity) |
24 |
24 |
25 # core entity and relation types which can't be removed |
25 # core entity and relation types which can't be removed |
26 CORE_ETYPES = list(BASE_TYPES) + ['EEType', 'ERType', 'EUser', 'EGroup', |
26 CORE_ETYPES = list(BASE_TYPES) + ['CWEType', 'CWRType', 'CWUser', 'CWGroup', |
27 'EConstraint', 'EFRDef', 'ENFRDef'] |
27 'CWConstraint', 'CWAttribute', 'CWRelation'] |
28 CORE_RTYPES = ['eid', 'creation_date', 'modification_date', |
28 CORE_RTYPES = ['eid', 'creation_date', 'modification_date', |
29 'login', 'upassword', 'name', |
29 'login', 'upassword', 'name', |
30 'is', 'instanceof', 'owned_by', 'created_by', 'in_group', |
30 'is', 'instanceof', 'owned_by', 'created_by', 'in_group', |
31 'relation_type', 'from_entity', 'to_entity', |
31 'relation_type', 'from_entity', 'to_entity', |
32 'constrainted_by', |
32 'constrainted_by', |
132 self.error('error while altering table %s: %s', table, ex) |
132 self.error('error while altering table %s: %s', table, ex) |
133 |
133 |
134 |
134 |
135 # deletion #################################################################### |
135 # deletion #################################################################### |
136 |
136 |
137 class DeleteEETypeOp(SchemaOperation): |
137 class DeleteCWETypeOp(SchemaOperation): |
138 """actually remove the entity type from the application's schema""" |
138 """actually remove the entity type from the application's schema""" |
139 def commit_event(self): |
139 def commit_event(self): |
140 try: |
140 try: |
141 # del_entity_type also removes entity's relations |
141 # del_entity_type also removes entity's relations |
142 self.schema.del_entity_type(self.kobj) |
142 self.schema.del_entity_type(self.kobj) |
143 except KeyError: |
143 except KeyError: |
144 # s/o entity type have already been deleted |
144 # s/o entity type have already been deleted |
145 pass |
145 pass |
146 |
146 |
147 def before_del_eetype(session, eid): |
147 def before_del_eetype(session, eid): |
148 """before deleting a EEType entity: |
148 """before deleting a CWEType entity: |
149 * check that we don't remove a core entity type |
149 * check that we don't remove a core entity type |
150 * cascade to delete related EFRDef and ENFRDef entities |
150 * cascade to delete related CWAttribute and CWRelation entities |
151 * instantiate an operation to delete the entity type on commit |
151 * instantiate an operation to delete the entity type on commit |
152 """ |
152 """ |
153 # final entities can't be deleted, don't care about that |
153 # final entities can't be deleted, don't care about that |
154 name = check_internal_entity(session, eid, CORE_ETYPES) |
154 name = check_internal_entity(session, eid, CORE_ETYPES) |
155 # delete every entities of this type |
155 # delete every entities of this type |
156 session.unsafe_execute('DELETE %s X' % name) |
156 session.unsafe_execute('DELETE %s X' % name) |
157 DropTableOp(session, table=SQL_PREFIX + name) |
157 DropTableOp(session, table=SQL_PREFIX + name) |
158 DeleteEETypeOp(session, name) |
158 DeleteCWETypeOp(session, name) |
159 |
159 |
160 def after_del_eetype(session, eid): |
160 def after_del_eetype(session, eid): |
161 # workflow cleanup |
161 # workflow cleanup |
162 session.execute('DELETE State X WHERE NOT X state_of Y') |
162 session.execute('DELETE State X WHERE NOT X state_of Y') |
163 session.execute('DELETE Transition X WHERE NOT X transition_of Y') |
163 session.execute('DELETE Transition X WHERE NOT X transition_of Y') |
164 |
164 |
165 |
165 |
166 class DeleteERTypeOp(SchemaOperation): |
166 class DeleteCWRTypeOp(SchemaOperation): |
167 """actually remove the relation type from the application's schema""" |
167 """actually remove the relation type from the application's schema""" |
168 def commit_event(self): |
168 def commit_event(self): |
169 try: |
169 try: |
170 self.schema.del_relation_type(self.kobj) |
170 self.schema.del_relation_type(self.kobj) |
171 except KeyError: |
171 except KeyError: |
172 # s/o entity type have already been deleted |
172 # s/o entity type have already been deleted |
173 pass |
173 pass |
174 |
174 |
175 def before_del_ertype(session, eid): |
175 def before_del_ertype(session, eid): |
176 """before deleting a ERType entity: |
176 """before deleting a CWRType entity: |
177 * check that we don't remove a core relation type |
177 * check that we don't remove a core relation type |
178 * cascade to delete related EFRDef and ENFRDef entities |
178 * cascade to delete related CWAttribute and CWRelation entities |
179 * instantiate an operation to delete the relation type on commit |
179 * instantiate an operation to delete the relation type on commit |
180 """ |
180 """ |
181 name = check_internal_entity(session, eid, CORE_RTYPES) |
181 name = check_internal_entity(session, eid, CORE_RTYPES) |
182 # delete relation definitions using this relation type |
182 # delete relation definitions using this relation type |
183 session.execute('DELETE EFRDef X WHERE X relation_type Y, Y eid %(x)s', |
183 session.execute('DELETE CWAttribute X WHERE X relation_type Y, Y eid %(x)s', |
184 {'x': eid}) |
184 {'x': eid}) |
185 session.execute('DELETE ENFRDef X WHERE X relation_type Y, Y eid %(x)s', |
185 session.execute('DELETE CWRelation X WHERE X relation_type Y, Y eid %(x)s', |
186 {'x': eid}) |
186 {'x': eid}) |
187 DeleteERTypeOp(session, name) |
187 DeleteCWRTypeOp(session, name) |
188 |
188 |
189 |
189 |
190 class DelErdefOp(SchemaOperation): |
190 class DelErdefOp(SchemaOperation): |
191 """actually remove the relation definition from the application's schema""" |
191 """actually remove the relation definition from the application's schema""" |
192 def commit_event(self): |
192 def commit_event(self): |
208 """ |
208 """ |
209 subjschema, rschema, objschema = session.repo.schema.schema_by_eid(rdefeid) |
209 subjschema, rschema, objschema = session.repo.schema.schema_by_eid(rdefeid) |
210 pendings = session.query_data('pendingeids', ()) |
210 pendings = session.query_data('pendingeids', ()) |
211 # first delete existing relation if necessary |
211 # first delete existing relation if necessary |
212 if rschema.is_final(): |
212 if rschema.is_final(): |
213 rdeftype = 'EFRDef' |
213 rdeftype = 'CWAttribute' |
214 else: |
214 else: |
215 rdeftype = 'ENFRDef' |
215 rdeftype = 'CWRelation' |
216 if not (subjschema.eid in pendings or objschema.eid in pendings): |
216 if not (subjschema.eid in pendings or objschema.eid in pendings): |
217 session.execute('DELETE X %s Y WHERE X is %s, Y is %s' |
217 session.execute('DELETE X %s Y WHERE X is %s, Y is %s' |
218 % (rschema, subjschema, objschema)) |
218 % (rschema, subjschema, objschema)) |
219 execute = session.unsafe_execute |
219 execute = session.unsafe_execute |
220 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R,' |
220 rset = execute('Any COUNT(X) WHERE X is %s, X relation_type R,' |
233 column=SQL_PREFIX + rschema.type) |
233 column=SQL_PREFIX + rschema.type) |
234 elif lastrel: |
234 elif lastrel: |
235 DropTableOp(session, table='%s_relation' % rschema.type) |
235 DropTableOp(session, table='%s_relation' % rschema.type) |
236 # if this is the last instance, drop associated relation type |
236 # if this is the last instance, drop associated relation type |
237 if lastrel and not rteid in pendings: |
237 if lastrel and not rteid in pendings: |
238 execute('DELETE ERType X WHERE X eid %(x)s', {'x': rteid}, 'x') |
238 execute('DELETE CWRType X WHERE X eid %(x)s', {'x': rteid}, 'x') |
239 DelErdefOp(session, (subjschema, rschema, objschema)) |
239 DelErdefOp(session, (subjschema, rschema, objschema)) |
240 |
240 |
241 |
241 |
242 # addition #################################################################### |
242 # addition #################################################################### |
243 |
243 |
244 class AddEETypeOp(EarlySchemaOperation): |
244 class AddCWETypeOp(EarlySchemaOperation): |
245 """actually add the entity type to the application's schema""" |
245 """actually add the entity type to the application's schema""" |
246 eid = None # make pylint happy |
246 eid = None # make pylint happy |
247 def commit_event(self): |
247 def commit_event(self): |
248 eschema = self.schema.add_entity_type(self.kobj) |
248 eschema = self.schema.add_entity_type(self.kobj) |
249 eschema.eid = self.eid |
249 eschema.eid = self.eid |
250 |
250 |
251 def before_add_eetype(session, entity): |
251 def before_add_eetype(session, entity): |
252 """before adding a EEType entity: |
252 """before adding a CWEType entity: |
253 * check that we are not using an existing entity type, |
253 * check that we are not using an existing entity type, |
254 """ |
254 """ |
255 name = entity['name'] |
255 name = entity['name'] |
256 schema = session.repo.schema |
256 schema = session.repo.schema |
257 if name in schema and schema[name].eid is not None: |
257 if name in schema and schema[name].eid is not None: |
258 raise RepositoryError('an entity type %s already exists' % name) |
258 raise RepositoryError('an entity type %s already exists' % name) |
259 |
259 |
260 def after_add_eetype(session, entity): |
260 def after_add_eetype(session, entity): |
261 """after adding a EEType entity: |
261 """after adding a CWEType entity: |
262 * create the necessary table |
262 * create the necessary table |
263 * set creation_date and modification_date by creating the necessary |
263 * set creation_date and modification_date by creating the necessary |
264 EFRDef entities |
264 CWAttribute entities |
265 * add owned_by relation by creating the necessary ENFRDef entity |
265 * add owned_by relation by creating the necessary CWRelation entity |
266 * register an operation to add the entity type to the application's |
266 * register an operation to add the entity type to the application's |
267 schema on commit |
267 schema on commit |
268 """ |
268 """ |
269 if entity.get('final'): |
269 if entity.get('final'): |
270 return |
270 return |
295 if sql.strip(): |
295 if sql.strip(): |
296 session.system_sql(sql) |
296 session.system_sql(sql) |
297 # register operation to modify the schema on commit |
297 # register operation to modify the schema on commit |
298 # this have to be done before adding other relations definitions |
298 # this have to be done before adding other relations definitions |
299 # or permission settings |
299 # or permission settings |
300 AddEETypeOp(session, etype, eid=entity.eid) |
300 AddCWETypeOp(session, etype, eid=entity.eid) |
301 # add meta creation_date, modification_date and owned_by relations |
301 # add meta creation_date, modification_date and owned_by relations |
302 for rql, kwargs in relrqls: |
302 for rql, kwargs in relrqls: |
303 session.execute(rql, kwargs) |
303 session.execute(rql, kwargs) |
304 |
304 |
305 |
305 |
306 class AddERTypeOp(EarlySchemaOperation): |
306 class AddCWRTypeOp(EarlySchemaOperation): |
307 """actually add the relation type to the application's schema""" |
307 """actually add the relation type to the application's schema""" |
308 eid = None # make pylint happy |
308 eid = None # make pylint happy |
309 def commit_event(self): |
309 def commit_event(self): |
310 rschema = self.schema.add_relation_type(self.kobj) |
310 rschema = self.schema.add_relation_type(self.kobj) |
311 rschema.set_default_groups() |
311 rschema.set_default_groups() |
312 rschema.eid = self.eid |
312 rschema.eid = self.eid |
313 |
313 |
314 def before_add_ertype(session, entity): |
314 def before_add_ertype(session, entity): |
315 """before adding a ERType entity: |
315 """before adding a CWRType entity: |
316 * check that we are not using an existing relation type, |
316 * check that we are not using an existing relation type, |
317 * register an operation to add the relation type to the application's |
317 * register an operation to add the relation type to the application's |
318 schema on commit |
318 schema on commit |
319 |
319 |
320 We don't know yeat this point if a table is necessary |
320 We don't know yeat this point if a table is necessary |
322 name = entity['name'] |
322 name = entity['name'] |
323 if name in session.repo.schema.relations(): |
323 if name in session.repo.schema.relations(): |
324 raise RepositoryError('a relation type %s already exists' % name) |
324 raise RepositoryError('a relation type %s already exists' % name) |
325 |
325 |
326 def after_add_ertype(session, entity): |
326 def after_add_ertype(session, entity): |
327 """after a ERType entity has been added: |
327 """after a CWRType entity has been added: |
328 * register an operation to add the relation type to the application's |
328 * register an operation to add the relation type to the application's |
329 schema on commit |
329 schema on commit |
330 We don't know yeat this point if a table is necessary |
330 We don't know yeat this point if a table is necessary |
331 """ |
331 """ |
332 AddERTypeOp(session, RelationType(name=entity['name'], |
332 AddCWRTypeOp(session, RelationType(name=entity['name'], |
333 description=entity.get('description'), |
333 description=entity.get('description'), |
334 meta=entity.get('meta', False), |
334 meta=entity.get('meta', False), |
335 inlined=entity.get('inlined', False), |
335 inlined=entity.get('inlined', False), |
336 symetric=entity.get('symetric', False)), |
336 symetric=entity.get('symetric', False)), |
337 eid=entity.eid) |
337 eid=entity.eid) |
437 session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
437 session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column), |
438 {'default': default}) |
438 {'default': default}) |
439 AddErdefOp(session, rdef) |
439 AddErdefOp(session, rdef) |
440 |
440 |
441 def after_add_efrdef(session, entity): |
441 def after_add_efrdef(session, entity): |
442 AddEFRDefPreCommitOp(session, entity=entity) |
442 AddCWAttributePreCommitOp(session, entity=entity) |
443 |
443 |
444 |
444 |
445 class AddENFRDefPreCommitOp(PreCommitOperation): |
445 class AddCWRelationPreCommitOp(PreCommitOperation): |
446 """an actual relation has been added: |
446 """an actual relation has been added: |
447 * if this is an inlined relation, add the necessary column |
447 * if this is an inlined relation, add the necessary column |
448 else if it's the first instance of this relation type, add the |
448 else if it's the first instance of this relation type, add the |
449 necessary table and set default permissions |
449 necessary table and set default permissions |
450 * register an operation to add the relation definition to the |
450 * register an operation to add the relation definition to the |
844 erschema.set_rqlexprs(self.perm, exprs) |
844 erschema.set_rqlexprs(self.perm, exprs) |
845 |
845 |
846 def after_add_permission(session, subject, rtype, object): |
846 def after_add_permission(session, subject, rtype, object): |
847 """added entity/relation *_permission, need to update schema""" |
847 """added entity/relation *_permission, need to update schema""" |
848 perm = rtype.split('_', 1)[0] |
848 perm = rtype.split('_', 1)[0] |
849 if session.describe(object)[0] == 'EGroup': |
849 if session.describe(object)[0] == 'CWGroup': |
850 AddGroupPermissionOp(session, perm, subject, object) |
850 AddGroupPermissionOp(session, perm, subject, object) |
851 else: # RQLExpression |
851 else: # RQLExpression |
852 expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR', |
852 expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR', |
853 {'x': object}, 'x')[0][0] |
853 {'x': object}, 'x')[0][0] |
854 AddRQLExpressionPermissionOp(session, perm, subject, expr) |
854 AddRQLExpressionPermissionOp(session, perm, subject, expr) |
904 skip the operation if the related type is being deleted |
904 skip the operation if the related type is being deleted |
905 """ |
905 """ |
906 if subject in session.query_data('pendingeids', ()): |
906 if subject in session.query_data('pendingeids', ()): |
907 return |
907 return |
908 perm = rtype.split('_', 1)[0] |
908 perm = rtype.split('_', 1)[0] |
909 if session.describe(object)[0] == 'EGroup': |
909 if session.describe(object)[0] == 'CWGroup': |
910 DelGroupPermissionOp(session, perm, subject, object) |
910 DelGroupPermissionOp(session, perm, subject, object) |
911 else: # RQLExpression |
911 else: # RQLExpression |
912 expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR', |
912 expr = session.execute('Any EXPR WHERE X eid %(x)s, X expression EXPR', |
913 {'x': object}, 'x')[0][0] |
913 {'x': object}, 'x')[0][0] |
914 DelRQLExpressionPermissionOp(session, perm, subject, expr) |
914 DelRQLExpressionPermissionOp(session, perm, subject, expr) |
923 |
923 |
924 def _register_schema_hooks(hm): |
924 def _register_schema_hooks(hm): |
925 """register schema related hooks on the hooks manager""" |
925 """register schema related hooks on the hooks manager""" |
926 # schema synchronisation ##################### |
926 # schema synchronisation ##################### |
927 # before/after add |
927 # before/after add |
928 hm.register_hook(before_add_eetype, 'before_add_entity', 'EEType') |
928 hm.register_hook(before_add_eetype, 'before_add_entity', 'CWEType') |
929 hm.register_hook(before_add_ertype, 'before_add_entity', 'ERType') |
929 hm.register_hook(before_add_ertype, 'before_add_entity', 'CWRType') |
930 hm.register_hook(after_add_eetype, 'after_add_entity', 'EEType') |
930 hm.register_hook(after_add_eetype, 'after_add_entity', 'CWEType') |
931 hm.register_hook(after_add_ertype, 'after_add_entity', 'ERType') |
931 hm.register_hook(after_add_ertype, 'after_add_entity', 'CWRType') |
932 hm.register_hook(after_add_efrdef, 'after_add_entity', 'EFRDef') |
932 hm.register_hook(after_add_efrdef, 'after_add_entity', 'CWAttribute') |
933 hm.register_hook(after_add_enfrdef, 'after_add_entity', 'ENFRDef') |
933 hm.register_hook(after_add_enfrdef, 'after_add_entity', 'CWRelation') |
934 # before/after update |
934 # before/after update |
935 hm.register_hook(before_update_eetype, 'before_update_entity', 'EEType') |
935 hm.register_hook(before_update_eetype, 'before_update_entity', 'CWEType') |
936 hm.register_hook(before_update_ertype, 'before_update_entity', 'ERType') |
936 hm.register_hook(before_update_ertype, 'before_update_entity', 'CWRType') |
937 hm.register_hook(after_update_ertype, 'after_update_entity', 'ERType') |
937 hm.register_hook(after_update_ertype, 'after_update_entity', 'CWRType') |
938 hm.register_hook(after_update_erdef, 'after_update_entity', 'EFRDef') |
938 hm.register_hook(after_update_erdef, 'after_update_entity', 'CWAttribute') |
939 hm.register_hook(after_update_erdef, 'after_update_entity', 'ENFRDef') |
939 hm.register_hook(after_update_erdef, 'after_update_entity', 'CWRelation') |
940 # before/after delete |
940 # before/after delete |
941 hm.register_hook(before_del_eetype, 'before_delete_entity', 'EEType') |
941 hm.register_hook(before_del_eetype, 'before_delete_entity', 'CWEType') |
942 hm.register_hook(after_del_eetype, 'after_delete_entity', 'EEType') |
942 hm.register_hook(after_del_eetype, 'after_delete_entity', 'CWEType') |
943 hm.register_hook(before_del_ertype, 'before_delete_entity', 'ERType') |
943 hm.register_hook(before_del_ertype, 'before_delete_entity', 'CWRType') |
944 hm.register_hook(after_del_relation_type, 'after_delete_relation', 'relation_type') |
944 hm.register_hook(after_del_relation_type, 'after_delete_relation', 'relation_type') |
945 hm.register_hook(rebuild_infered_relations, 'after_add_relation', 'specializes') |
945 hm.register_hook(rebuild_infered_relations, 'after_add_relation', 'specializes') |
946 hm.register_hook(rebuild_infered_relations, 'after_delete_relation', 'specializes') |
946 hm.register_hook(rebuild_infered_relations, 'after_delete_relation', 'specializes') |
947 # constraints synchronization hooks |
947 # constraints synchronization hooks |
948 hm.register_hook(after_add_econstraint, 'after_add_entity', 'EConstraint') |
948 hm.register_hook(after_add_econstraint, 'after_add_entity', 'CWConstraint') |
949 hm.register_hook(after_update_econstraint, 'after_update_entity', 'EConstraint') |
949 hm.register_hook(after_update_econstraint, 'after_update_entity', 'CWConstraint') |
950 hm.register_hook(before_delete_constrained_by, 'before_delete_relation', 'constrained_by') |
950 hm.register_hook(before_delete_constrained_by, 'before_delete_relation', 'constrained_by') |
951 hm.register_hook(after_add_constrained_by, 'after_add_relation', 'constrained_by') |
951 hm.register_hook(after_add_constrained_by, 'after_add_relation', 'constrained_by') |
952 # permissions synchronisation ################ |
952 # permissions synchronisation ################ |
953 for perm in ('read_permission', 'add_permission', |
953 for perm in ('read_permission', 'add_permission', |
954 'delete_permission', 'update_permission'): |
954 'delete_permission', 'update_permission'): |