mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
R: Improve cst creation propagation
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
This commit is contained in:
parent
53998cfa92
commit
9170692f33
|
@ -22,8 +22,6 @@ from .Substitution import Substitution
|
||||||
|
|
||||||
CstMapping = dict[str, Constituenta]
|
CstMapping = dict[str, Constituenta]
|
||||||
|
|
||||||
# TODO: add more variety tests for cascade resolutions model
|
|
||||||
|
|
||||||
|
|
||||||
class ChangeManager:
|
class ChangeManager:
|
||||||
''' Change propagation wrapper for OSS. '''
|
''' Change propagation wrapper for OSS. '''
|
||||||
|
@ -121,25 +119,29 @@ class ChangeManager:
|
||||||
self.cache = ChangeManager.Cache(self.oss)
|
self.cache = ChangeManager.Cache(self.oss)
|
||||||
|
|
||||||
|
|
||||||
def on_create_cst(self, new_cst: Constituenta, source: RSForm) -> None:
|
def after_create_cst(self, cst_list: list[Constituenta], source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when new constituent is created. '''
|
''' Trigger cascade resolutions when new constituent is created. '''
|
||||||
self.cache.insert(source)
|
self.cache.insert(source)
|
||||||
depend_aliases = new_cst.extract_references()
|
inserted_aliases = [cst.alias for cst in cst_list]
|
||||||
|
depend_aliases: set[str] = set()
|
||||||
|
for new_cst in cst_list:
|
||||||
|
depend_aliases.update(new_cst.extract_references())
|
||||||
|
depend_aliases.difference_update(inserted_aliases)
|
||||||
alias_mapping: CstMapping = {}
|
alias_mapping: CstMapping = {}
|
||||||
for alias in depend_aliases:
|
for alias in depend_aliases:
|
||||||
cst = source.cache.by_alias.get(alias)
|
cst = source.cache.by_alias.get(alias)
|
||||||
if cst is not None:
|
if cst is not None:
|
||||||
alias_mapping[alias] = cst
|
alias_mapping[alias] = cst
|
||||||
operation = self.cache.get_operation(source)
|
operation = self.cache.get_operation(source)
|
||||||
self._cascade_create_cst(new_cst, operation, alias_mapping)
|
self._cascade_create_cst(cst_list, operation, alias_mapping)
|
||||||
|
|
||||||
def on_change_cst_type(self, target: Constituenta, source: RSForm) -> None:
|
def after_change_cst_type(self, target: Constituenta, source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||||
self.cache.insert(source)
|
self.cache.insert(source)
|
||||||
operation = self.cache.get_operation(source)
|
operation = self.cache.get_operation(source)
|
||||||
self._cascade_change_cst_type(target.pk, target.cst_type, operation)
|
self._cascade_change_cst_type(target.pk, target.cst_type, operation)
|
||||||
|
|
||||||
def on_update_cst(self, target: Constituenta, data: dict, old_data: dict, source: RSForm) -> None:
|
def after_update_cst(self, target: Constituenta, data: dict, old_data: dict, source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when constituenta data is changed. '''
|
''' Trigger cascade resolutions when constituenta data is changed. '''
|
||||||
self.cache.insert(source)
|
self.cache.insert(source)
|
||||||
operation = self.cache.get_operation(source)
|
operation = self.cache.get_operation(source)
|
||||||
|
@ -157,32 +159,7 @@ class ChangeManager:
|
||||||
operation = self.cache.get_operation(source)
|
operation = self.cache.get_operation(source)
|
||||||
self._cascade_before_delete(target, operation)
|
self._cascade_before_delete(target, operation)
|
||||||
|
|
||||||
def _cascade_before_delete(self, target: list[Constituenta], operation: Operation) -> None:
|
def _cascade_create_cst(self, cst_list: list[Constituenta], operation: Operation, mapping: CstMapping) -> None:
|
||||||
children = self.cache.graph.outputs[operation.pk]
|
|
||||||
if len(children) == 0:
|
|
||||||
return
|
|
||||||
self.cache.ensure_loaded()
|
|
||||||
for child_id in children:
|
|
||||||
child_operation = self.cache.operation_by_id[child_id]
|
|
||||||
child_schema = self.cache.get_schema(child_operation)
|
|
||||||
if child_schema is None:
|
|
||||||
continue
|
|
||||||
child_schema.cache.ensure_loaded()
|
|
||||||
|
|
||||||
# TODO: check if substitutions are affected. Undo substitutions before deletion
|
|
||||||
|
|
||||||
child_target_cst = []
|
|
||||||
child_target_ids = []
|
|
||||||
for cst in target:
|
|
||||||
successor_id = self.cache.get_successor_for(cst.pk, child_id, ignore_substitution=True)
|
|
||||||
if successor_id is not None:
|
|
||||||
child_target_ids.append(successor_id)
|
|
||||||
child_target_cst.append(child_schema.cache.by_id[successor_id])
|
|
||||||
self._cascade_before_delete(child_target_cst, child_operation)
|
|
||||||
self.cache.remove_cst(child_target_ids, child_id)
|
|
||||||
child_schema.delete_cst(child_target_cst)
|
|
||||||
|
|
||||||
def _cascade_create_cst(self, prototype: Constituenta, operation: Operation, mapping: CstMapping) -> None:
|
|
||||||
children = self.cache.graph.outputs[operation.pk]
|
children = self.cache.graph.outputs[operation.pk]
|
||||||
if len(children) == 0:
|
if len(children) == 0:
|
||||||
return
|
return
|
||||||
|
@ -199,16 +176,17 @@ class ChangeManager:
|
||||||
self.cache.ensure_loaded()
|
self.cache.ensure_loaded()
|
||||||
new_mapping = self._transform_mapping(mapping, child_operation, child_schema)
|
new_mapping = self._transform_mapping(mapping, child_operation, child_schema)
|
||||||
alias_mapping = {alias: cst.alias for alias, cst in new_mapping.items()}
|
alias_mapping = {alias: cst.alias for alias, cst in new_mapping.items()}
|
||||||
insert_where = self._determine_insert_position(prototype, child_operation, source_schema, child_schema)
|
insert_where = self._determine_insert_position(cst_list[0], child_operation, source_schema, child_schema)
|
||||||
new_cst = child_schema.insert_copy([prototype], insert_where, alias_mapping)[0]
|
new_cst_list = child_schema.insert_copy(cst_list, insert_where, alias_mapping)
|
||||||
|
for index, cst in enumerate(new_cst_list):
|
||||||
new_inheritance = Inheritance.objects.create(
|
new_inheritance = Inheritance.objects.create(
|
||||||
operation=child_operation,
|
operation=child_operation,
|
||||||
child=new_cst,
|
child=cst,
|
||||||
parent=prototype
|
parent=cst_list[index]
|
||||||
)
|
)
|
||||||
self.cache.insert_inheritance(new_inheritance)
|
self.cache.insert_inheritance(new_inheritance)
|
||||||
new_mapping = {alias_mapping[alias]: cst for alias, cst in new_mapping.items()}
|
new_mapping = {alias_mapping[alias]: cst for alias, cst in new_mapping.items()}
|
||||||
self._cascade_create_cst(new_cst, child_operation, new_mapping)
|
self._cascade_create_cst(new_cst_list, child_operation, new_mapping)
|
||||||
|
|
||||||
def _cascade_change_cst_type(self, cst_id: int, ctype: CstType, operation: Operation) -> None:
|
def _cascade_change_cst_type(self, cst_id: int, ctype: CstType, operation: Operation) -> None:
|
||||||
children = self.cache.graph.outputs[operation.pk]
|
children = self.cache.graph.outputs[operation.pk]
|
||||||
|
@ -256,6 +234,31 @@ class ChangeManager:
|
||||||
new_mapping = {alias_mapping[alias]: cst for alias, cst in new_mapping.items()}
|
new_mapping = {alias_mapping[alias]: cst for alias, cst in new_mapping.items()}
|
||||||
self._cascade_update_cst(successor_id, child_operation, new_data, new_old_data, new_mapping)
|
self._cascade_update_cst(successor_id, child_operation, new_data, new_old_data, new_mapping)
|
||||||
|
|
||||||
|
def _cascade_before_delete(self, target: list[Constituenta], operation: Operation) -> None:
|
||||||
|
children = self.cache.graph.outputs[operation.pk]
|
||||||
|
if len(children) == 0:
|
||||||
|
return
|
||||||
|
self.cache.ensure_loaded()
|
||||||
|
for child_id in children:
|
||||||
|
child_operation = self.cache.operation_by_id[child_id]
|
||||||
|
child_schema = self.cache.get_schema(child_operation)
|
||||||
|
if child_schema is None:
|
||||||
|
continue
|
||||||
|
child_schema.cache.ensure_loaded()
|
||||||
|
|
||||||
|
# TODO: check if substitutions are affected. Undo substitutions before deletion
|
||||||
|
|
||||||
|
child_target_cst = []
|
||||||
|
child_target_ids = []
|
||||||
|
for cst in target:
|
||||||
|
successor_id = self.cache.get_successor_for(cst.pk, child_id, ignore_substitution=True)
|
||||||
|
if successor_id is not None:
|
||||||
|
child_target_ids.append(successor_id)
|
||||||
|
child_target_cst.append(child_schema.cache.by_id[successor_id])
|
||||||
|
self._cascade_before_delete(child_target_cst, child_operation)
|
||||||
|
self.cache.remove_cst(child_target_ids, child_id)
|
||||||
|
child_schema.delete_cst(child_target_cst)
|
||||||
|
|
||||||
def _transform_mapping(self, mapping: CstMapping, operation: Operation, schema: RSForm) -> CstMapping:
|
def _transform_mapping(self, mapping: CstMapping, operation: Operation, schema: RSForm) -> CstMapping:
|
||||||
if len(mapping) == 0:
|
if len(mapping) == 0:
|
||||||
return mapping
|
return mapping
|
||||||
|
|
|
@ -14,25 +14,25 @@ class PropagationFacade:
|
||||||
''' Change propagation API. '''
|
''' Change propagation API. '''
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def on_create_cst(cls, new_cst: Constituenta, source: RSForm) -> None:
|
def after_create_cst(cls, new_cst: list[Constituenta], source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when new constituent is created. '''
|
''' Trigger cascade resolutions when new constituent is created. '''
|
||||||
hosts = _get_oss_hosts(source.model)
|
hosts = _get_oss_hosts(source.model)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
ChangeManager(host).on_create_cst(new_cst, source)
|
ChangeManager(host).after_create_cst(new_cst, source)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def on_change_cst_type(cls, target: Constituenta, source: RSForm) -> None:
|
def after_change_cst_type(cls, target: Constituenta, source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||||
hosts = _get_oss_hosts(source.model)
|
hosts = _get_oss_hosts(source.model)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
ChangeManager(host).on_change_cst_type(target, source)
|
ChangeManager(host).after_change_cst_type(target, source)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def on_update_cst(cls, target: Constituenta, data: dict, old_data: dict, source: RSForm) -> None:
|
def after_update_cst(cls, target: Constituenta, data: dict, old_data: dict, source: RSForm) -> None:
|
||||||
''' Trigger cascade resolutions when constituenta data is changed. '''
|
''' Trigger cascade resolutions when constituenta data is changed. '''
|
||||||
hosts = _get_oss_hosts(source.model)
|
hosts = _get_oss_hosts(source.model)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
ChangeManager(host).on_update_cst(target, data, old_data, source)
|
ChangeManager(host).after_update_cst(target, data, old_data, source)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def before_delete(cls, target: list[Constituenta], source: RSForm) -> None:
|
def before_delete(cls, target: list[Constituenta], source: RSForm) -> None:
|
||||||
|
|
|
@ -448,7 +448,7 @@ class RSForm:
|
||||||
data=data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
def produce_structure(self, target: Constituenta, parse: dict) -> list[int]:
|
def produce_structure(self, target: Constituenta, parse: dict) -> list[Constituenta]:
|
||||||
''' Add constituents for each structural element of the target. '''
|
''' Add constituents for each structural element of the target. '''
|
||||||
expressions = generate_structure(
|
expressions = generate_structure(
|
||||||
alias=target.alias,
|
alias=target.alias,
|
||||||
|
@ -474,11 +474,11 @@ class RSForm:
|
||||||
definition_formal=text,
|
definition_formal=text,
|
||||||
cst_type=cst_type
|
cst_type=cst_type
|
||||||
)
|
)
|
||||||
result.append(new_item.pk)
|
result.append(new_item)
|
||||||
free_index = free_index + 1
|
free_index = free_index + 1
|
||||||
position = position + 1
|
position = position + 1
|
||||||
|
|
||||||
self.cache.clear()
|
self.cache.insert_multi(result)
|
||||||
self.save()
|
self.save()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
schema = m.RSForm(self._get_item())
|
schema = m.RSForm(self._get_item())
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
new_cst = schema.create_cst(data, insert_after)
|
new_cst = schema.create_cst(data, insert_after)
|
||||||
PropagationFacade.on_create_cst(new_cst, schema)
|
PropagationFacade.after_create_cst([new_cst], schema)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_201_CREATED,
|
status=c.HTTP_201_CREATED,
|
||||||
data={
|
data={
|
||||||
|
@ -118,7 +118,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
data = serializer.validated_data['item_data']
|
data = serializer.validated_data['item_data']
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
old_data = schema.update_cst(cst, data)
|
old_data = schema.update_cst(cst, data)
|
||||||
PropagationFacade.on_update_cst(cst, data, old_data, schema)
|
PropagationFacade.after_update_cst(cst, data, old_data, schema)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data=s.CstSerializer(m.Constituenta.objects.get(pk=request.data['target'])).data
|
data=s.CstSerializer(m.Constituenta.objects.get(pk=request.data['target'])).data
|
||||||
|
@ -158,11 +158,12 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
schema = m.RSForm(model)
|
schema = m.RSForm(model)
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
result = schema.produce_structure(cst, cst_parse)
|
new_cst = schema.produce_structure(cst, cst_parse)
|
||||||
|
PropagationFacade.after_create_cst(new_cst, schema)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data={
|
data={
|
||||||
'cst_list': result,
|
'cst_list': [cst.pk for cst in new_cst],
|
||||||
'schema': s.RSFormParseSerializer(schema.model).data
|
'schema': s.RSFormParseSerializer(schema.model).data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -195,7 +196,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
schema.apply_mapping(mapping=mapping, change_aliases=False)
|
schema.apply_mapping(mapping=mapping, change_aliases=False)
|
||||||
cst.refresh_from_db()
|
cst.refresh_from_db()
|
||||||
if changed_type:
|
if changed_type:
|
||||||
PropagationFacade.on_change_cst_type(cst, schema)
|
PropagationFacade.after_change_cst_type(cst, schema)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data={
|
data={
|
||||||
|
@ -577,6 +578,8 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
new_items = receiver.insert_copy(items)
|
new_items = receiver.insert_copy(items)
|
||||||
|
PropagationFacade.after_create_cst(new_items, receiver)
|
||||||
|
|
||||||
substitutions: list[tuple[m.Constituenta, m.Constituenta]] = []
|
substitutions: list[tuple[m.Constituenta, m.Constituenta]] = []
|
||||||
for substitution in serializer.validated_data['substitutions']:
|
for substitution in serializer.validated_data['substitutions']:
|
||||||
original = cast(m.Constituenta, substitution['original'])
|
original = cast(m.Constituenta, substitution['original'])
|
||||||
|
@ -589,6 +592,9 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
||||||
replacement = new_items[index]
|
replacement = new_items[index]
|
||||||
substitutions.append((original, replacement))
|
substitutions.append((original, replacement))
|
||||||
receiver.substitute(substitutions)
|
receiver.substitute(substitutions)
|
||||||
|
|
||||||
|
# TODO: propagate substitutions
|
||||||
|
|
||||||
receiver.restore_order()
|
receiver.restore_order()
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user