R: Refactoring cache models pt2
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Backend CI / notify-failure (push) Has been cancelled

This commit is contained in:
Ivan 2025-08-03 15:47:00 +03:00
parent 25ec175d79
commit 2bacaf34b6
8 changed files with 138 additions and 97 deletions

View File

@ -1,7 +1,7 @@
''' Models: OSS API. '''
# pylint: disable=duplicate-code
from typing import Optional, cast
from typing import Optional
from cctext import extract_entities
from rest_framework.serializers import ValidationError
@ -59,18 +59,17 @@ class OperationSchemaCached:
schema = self.cache.get_schema(operation)
children = self.cache.graph.outputs[target]
if schema is not None and len(children) > 0:
ids = [cst.pk for cst in schema.cache.constituents]
if not keep_constituents:
self.before_delete_cst(schema, schema.cache.constituents)
self.before_delete_cst(schema.model.pk, ids)
else:
items = schema.cache.constituents
ids = [cst.pk for cst in items]
inheritance_to_delete: list[Inheritance] = []
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
self._undo_substitutions_cst(items, child_operation, child_schema)
self._undo_substitutions_cst(ids, child_operation, child_schema)
for item in self.cache.inheritance[child_id]:
if item.parent_id in ids:
inheritance_to_delete.append(item)
@ -91,7 +90,7 @@ class OperationSchemaCached:
if old_schema is not None:
if has_children:
self.before_delete_cst(old_schema, old_schema.cache.constituents)
self.before_delete_cst(old_schema.model.pk, [cst.pk for cst in old_schema.cache.constituents])
self.cache.remove_schema(old_schema)
operation.setQ_result(schema)
@ -238,19 +237,17 @@ class OperationSchemaCached:
receiver.model.save(update_fields=['time_update'])
return True
def relocate_down(self, source: RSFormCached, destination: RSFormCached, items: list[Constituenta]):
def relocate_down(self, source: RSFormCached, destination: RSFormCached, items: list[int]):
''' Move list of Constituents to destination Schema inheritor. '''
self.cache.ensure_loaded_subs()
self.cache.insert_schema(source)
self.cache.insert_schema(destination)
operation = self.cache.get_operation(destination.model.pk)
self._undo_substitutions_cst(items, operation, destination)
inheritance_to_delete = [item for item in self.cache.inheritance[operation.pk] if item.parent_id in items]
for item in inheritance_to_delete:
self.cache.remove_inheritance(item)
Inheritance.objects.filter(operation_id=operation.pk, parent__in=items).delete()
Inheritance.objects.filter(operation_id=operation.pk, parent_id__in=items).delete()
def relocate_up(self, source: RSFormCached, destination: RSFormCached,
items: list[Constituenta]) -> list[Constituenta]:
@ -285,6 +282,7 @@ class OperationSchemaCached:
exclude: Optional[list[int]] = None
) -> None:
''' Trigger cascade resolutions when new Constituenta is created. '''
source.cache.ensure_loaded()
self.cache.insert_schema(source)
inserted_aliases = [cst.alias for cst in cst_list]
depend_aliases: set[str] = set()
@ -299,12 +297,12 @@ class OperationSchemaCached:
operation = self.cache.get_operation(source.model.pk)
self._cascade_inherit_cst(operation.pk, source, cst_list, alias_mapping, exclude)
def after_change_cst_type(self, target: Constituenta) -> None:
def after_change_cst_type(self, schemaID: int, target: int, new_type: CstType) -> None:
''' Trigger cascade resolutions when Constituenta type is changed. '''
operation = self.cache.get_operation(target.schema.pk)
self._cascade_change_cst_type(operation.pk, target.pk, cast(CstType, target.cst_type))
operation = self.cache.get_operation(schemaID)
self._cascade_change_cst_type(operation.pk, target, new_type)
def after_update_cst(self, source: RSFormCached, target: Constituenta, data: dict, old_data: dict) -> None:
def after_update_cst(self, source: RSFormCached, target: int, data: dict, old_data: dict) -> None:
''' Trigger cascade resolutions when Constituenta data is changed. '''
self.cache.insert_schema(source)
operation = self.cache.get_operation(source.model.pk)
@ -316,16 +314,15 @@ class OperationSchemaCached:
alias_mapping[alias] = cst
self._cascade_update_cst(
operation=operation.pk,
cst_id=target.pk,
cst_id=target,
data=data,
old_data=old_data,
mapping=alias_mapping
)
def before_delete_cst(self, source: RSFormCached, target: list[Constituenta]) -> None:
def before_delete_cst(self, sourceID: int, target: list[int]) -> None:
''' Trigger cascade resolutions before Constituents are deleted. '''
self.cache.insert_schema(source)
operation = self.cache.get_operation(source.model.pk)
operation = self.cache.get_operation(sourceID)
self._cascade_delete_inherited(operation.pk, target)
def before_substitute(self, schemaID: int, substitutions: CstSubstitution) -> None:
@ -340,7 +337,7 @@ class OperationSchemaCached:
for argument in arguments:
parent_schema = self.cache.get_schema(argument)
if parent_schema is not None:
self._execute_delete_inherited(target.pk, parent_schema.cache.constituents)
self._execute_delete_inherited(target.pk, [cst.pk for cst in parent_schema.cache.constituents])
def after_create_arguments(self, target: Operation, arguments: list[Operation]) -> None:
''' Trigger cascade resolutions after arguments are created. '''
@ -443,7 +440,7 @@ class OperationSchemaCached:
new_data = self._prepare_update_data(successor, data, old_data, alias_mapping)
if len(new_data) == 0:
continue
new_old_data = child_schema.update_cst(successor, new_data)
new_old_data = child_schema.update_cst(successor.pk, new_data)
if len(new_old_data) == 0:
continue
new_mapping = {alias_mapping[alias]: cst for alias, cst in new_mapping.items()}
@ -455,7 +452,7 @@ class OperationSchemaCached:
mapping=new_mapping
)
def _cascade_delete_inherited(self, operation: int, target: list[Constituenta]) -> None:
def _cascade_delete_inherited(self, operation: int, target: list[int]) -> None:
children = self.cache.graph.outputs[operation]
if len(children) == 0:
return
@ -463,18 +460,17 @@ class OperationSchemaCached:
for child_id in children:
self._execute_delete_inherited(child_id, target)
def _execute_delete_inherited(self, operation_id: int, parent_cst: list[Constituenta]) -> None:
def _execute_delete_inherited(self, operation_id: int, parent_ids: list[int]) -> None:
operation = self.cache.operation_by_id[operation_id]
schema = self.cache.get_schema(operation)
if schema is None:
return
self._undo_substitutions_cst(parent_cst, operation, schema)
target_ids = self.cache.get_inheritors_list([cst.pk for cst in parent_cst], operation_id)
target_cst = [schema.cache.by_id[cst_id] for cst_id in target_ids]
self._cascade_delete_inherited(operation_id, target_cst)
if len(target_cst) > 0:
self._undo_substitutions_cst(parent_ids, operation, schema)
target_ids = self.cache.get_inheritors_list(parent_ids, operation_id)
self._cascade_delete_inherited(operation_id, target_ids)
if len(target_ids) > 0:
self.cache.remove_cst(operation_id, target_ids)
schema.delete_cst(target_cst)
schema.delete_cst(target_ids)
def _cascade_before_substitute(self, substitutions: CstSubstitution, operation: Operation) -> None:
children = self.cache.graph.outputs[operation.pk]
@ -635,8 +631,7 @@ class OperationSchemaCached:
result.append((schema.cache.by_id[new_original_id], schema.cache.by_id[new_substitution_id]))
return result
def _undo_substitutions_cst(self, target: list[Constituenta], operation: Operation, schema: RSFormCached) -> None:
target_ids = [cst.pk for cst in target]
def _undo_substitutions_cst(self, target_ids: list[int], operation: Operation, schema: RSFormCached) -> None:
to_process = []
for sub in self.cache.substitutions[operation.pk]:
if sub.original_id in target_ids or sub.substitution_id in target_ids:

View File

@ -2,7 +2,7 @@
from typing import Optional
from apps.library.models import LibraryItem, LibraryItemType
from apps.rsform.models import Constituenta, RSFormCached
from apps.rsform.models import Constituenta, CstType, RSFormCached
from .OperationSchemaCached import CstSubstitution, OperationSchemaCached
@ -25,17 +25,18 @@ class PropagationFacade:
OperationSchemaCached(host).after_create_cst(source, new_cst)
@staticmethod
def after_change_cst_type(target: Constituenta, exclude: Optional[list[int]] = None) -> None:
def after_change_cst_type(sourceID: int, target: int, new_type: CstType,
exclude: Optional[list[int]] = None) -> None:
''' Trigger cascade resolutions when constituenta type is changed. '''
hosts = _get_oss_hosts(target.schema.pk)
hosts = _get_oss_hosts(sourceID)
for host in hosts:
if exclude is None or host.pk not in exclude:
OperationSchemaCached(host).after_change_cst_type(target)
OperationSchemaCached(host).after_change_cst_type(sourceID, target, new_type)
@staticmethod
def after_update_cst(
source: RSFormCached,
target: Constituenta,
target: int,
data: dict,
old_data: dict,
exclude: Optional[list[int]] = None
@ -47,13 +48,13 @@ class PropagationFacade:
OperationSchemaCached(host).after_update_cst(source, target, data, old_data)
@staticmethod
def before_delete_cst(source: RSFormCached, target: list[Constituenta],
def before_delete_cst(sourceID: int, target: list[int],
exclude: Optional[list[int]] = None) -> None:
''' Trigger cascade resolutions before constituents are deleted. '''
hosts = _get_oss_hosts(source.model.pk)
hosts = _get_oss_hosts(sourceID)
for host in hosts:
if exclude is None or host.pk not in exclude:
OperationSchemaCached(host).before_delete_cst(source, target)
OperationSchemaCached(host).before_delete_cst(sourceID, target)
@staticmethod
def before_substitute(sourceID: int, substitutions: CstSubstitution,
@ -75,5 +76,5 @@ class PropagationFacade:
if len(hosts) == 0:
return
schema = RSFormCached(item)
PropagationFacade.before_delete_cst(schema, list(schema.constituentsQ().order_by('order')), exclude)
ids = list(Constituenta.objects.filter(schema=item).order_by('order').values_list('pk', flat=True))
PropagationFacade.before_delete_cst(item.pk, ids, exclude)

View File

@ -118,9 +118,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
serializer = s.LayoutSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
item = self._get_item()
with transaction.atomic():
m.Layout.update_data(pk, serializer.validated_data['data'])
item.save(update_fields=['time_update'])
return Response(status=c.HTTP_200_OK, data=s.OperationSchemaSerializer(item).data)
@extend_schema(
@ -143,13 +145,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
children_blocks: list[m.Block] = serializer.validated_data['children_blocks']
children_operations: list[m.Operation] = serializer.validated_data['children_operations']
with transaction.atomic():
oss = m.OperationSchema(item)
new_block = oss.create_block(**serializer.validated_data['item_data'])
layout.append({
'nodeID': 'b' + str(new_block.pk),
@ -197,8 +199,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
block: m.Block = cast(m.Block, serializer.validated_data['target'])
with transaction.atomic():
if 'title' in serializer.validated_data['item_data']:
block.title = serializer.validated_data['item_data']['title']
@ -211,6 +213,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
layout = serializer.validated_data['layout']
m.Layout.update_data(pk, layout)
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.OperationSchemaSerializer(item).data
@ -236,12 +239,12 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
block = cast(m.Block, serializer.validated_data['target'])
layout = serializer.validated_data['layout']
layout = [x for x in layout if x['nodeID'] != 'b' + str(block.pk)]
with transaction.atomic():
oss = m.OperationSchema(item)
oss.delete_block(block)
m.Layout.update_data(pk, layout)
item.save(update_fields=['time_update'])
@ -271,8 +274,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
layout = serializer.validated_data['layout']
with transaction.atomic():
m.Layout.update_data(pk, layout)
for operation in serializer.validated_data['operations']:
@ -308,13 +311,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
data = serializer.validated_data['item_data']
data['operation_type'] = m.OperationType.INPUT
with transaction.atomic():
oss = m.OperationSchema(item)
new_operation = oss.create_operation(**serializer.validated_data['item_data'])
layout.append({
'nodeID': 'o' + str(new_operation.pk),
@ -356,9 +359,9 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
with transaction.atomic():
source = cast(m.Operation, serializer.validated_data['source_operation'])
alias = '+' + source.alias
@ -426,15 +429,15 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
data = serializer.validated_data['item_data']
data['operation_type'] = m.OperationType.INPUT
if not serializer.validated_data['clone_source']:
data['result'] = serializer.validated_data['source']
with transaction.atomic():
oss = m.OperationSchema(item)
new_operation = oss.create_operation(**serializer.validated_data['item_data'])
layout.append({
'nodeID': 'o' + str(new_operation.pk),
@ -481,11 +484,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
with transaction.atomic():
oss = m.OperationSchema(item)
target = cast(m.Operation, serializer.validated_data['target'])
new_operation = oss.create_reference(target)
layout.append({
@ -526,13 +529,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
position = serializer.validated_data['position']
data = serializer.validated_data['item_data']
data['operation_type'] = m.OperationType.SYNTHESIS
with transaction.atomic():
oss = m.OperationSchema(item)
new_operation = oss.create_operation(**serializer.validated_data['item_data'])
layout.append({
'nodeID': 'o' + str(new_operation.pk),
@ -575,10 +578,10 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
oss = m.OperationSchemaCached(item)
with transaction.atomic():
oss = m.OperationSchemaCached(item)
if 'layout' in serializer.validated_data:
layout = serializer.validated_data['layout']
m.Layout.update_data(pk, layout)
@ -630,13 +633,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchemaCached(item)
operation = cast(m.Operation, serializer.validated_data['target'])
old_schema = operation.result
layout = serializer.validated_data['layout']
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
with transaction.atomic():
oss = m.OperationSchemaCached(item)
oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents'])
m.Layout.update_data(pk, layout)
if old_schema is not None:
@ -673,12 +676,12 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
oss = m.OperationSchemaCached(item)
operation = cast(m.Operation, serializer.validated_data['target'])
layout = serializer.validated_data['layout']
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
with transaction.atomic():
oss = m.OperationSchemaCached(item)
m.Layout.update_data(pk, layout)
oss.delete_reference(operation, serializer.validated_data['keep_connections'])
item.save(update_fields=['time_update'])
@ -708,7 +711,6 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
if len(operation.getQ_arguments()) > 0:
raise serializers.ValidationError({
@ -718,10 +720,10 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
raise serializers.ValidationError({
'target': msg.operationResultNotEmpty(operation.alias)
})
oss = m.OperationSchema(item)
layout = serializer.validated_data['layout']
with transaction.atomic():
oss = m.OperationSchema(item)
m.Layout.update_data(pk, layout)
schema = oss.create_input(operation)
item.save(update_fields=['time_update'])
@ -769,9 +771,10 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
raise serializers.ValidationError({
'input': msg.operationInputAlreadyConnected()
})
oss = m.OperationSchemaCached(item)
old_schema = target_operation.result
with transaction.atomic():
oss = m.OperationSchemaCached(item)
if old_schema is not None:
if old_schema.is_synced(item):
old_schema.visible = True
@ -805,7 +808,6 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
context={'oss': item}
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
if operation.operation_type != m.OperationType.SYNTHESIS:
raise serializers.ValidationError({
@ -815,10 +817,10 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
raise serializers.ValidationError({
'target': msg.operationResultNotEmpty(operation.alias)
})
oss = m.OperationSchemaCached(item)
layout = serializer.validated_data['layout']
with transaction.atomic():
oss = m.OperationSchemaCached(item)
oss.execute_operation(operation)
m.Layout.update_data(pk, layout)
item.save(update_fields=['time_update'])
@ -877,17 +879,17 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
''' Relocate constituents from one schema to another. '''
serializer = s.RelocateConstituentsSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.validated_data
oss = m.OperationSchemaCached(LibraryItem.objects.get(pk=data['oss']))
source = RSFormCached(LibraryItem.objects.get(pk=data['source']))
destination = RSFormCached(LibraryItem.objects.get(pk=data['destination']))
ids = [cst.pk for cst in data['items']]
with transaction.atomic():
oss = m.OperationSchemaCached(LibraryItem.objects.get(pk=data['oss']))
source = RSFormCached(LibraryItem.objects.get(pk=data['source']))
destination = RSFormCached(LibraryItem.objects.get(pk=data['destination']))
if data['move_down']:
oss.relocate_down(source, destination, data['items'])
m.PropagationFacade.before_delete_cst(source, data['items'])
source.delete_cst(data['items'])
oss.relocate_down(source, destination, ids)
m.PropagationFacade.before_delete_cst(data['source'], ids)
source.delete_cst(ids)
else:
new_items = oss.relocate_up(source, destination, data['items'])
m.PropagationFacade.after_create_cst(destination, new_items, exclude=[oss.model.pk])

View File

@ -233,6 +233,17 @@ class RSForm:
count_bot += 1
Constituenta.objects.bulk_update(cst_list, ['order'])
def delete_cst(self, target: list[Constituenta]) -> None:
''' Delete multiple constituents. '''
ids = [cst.pk for cst in target]
mapping = {cst.alias: DELETED_ALIAS for cst in target}
Constituenta.objects.filter(pk__in=ids).delete()
all_cst = Constituenta.objects.filter(schema=self.model).only(
'alias', 'definition_formal', 'term_raw', 'definition_raw', 'order'
).order_by('order')
RSForm.apply_mapping(mapping, all_cst, change_aliases=False)
RSForm.save_order(all_cst)
def reset_aliases(self) -> None:
''' Recreate all aliases based on constituents order. '''
bases = cast(dict[str, int], {})

View File

@ -153,12 +153,12 @@ class RSFormCached:
return result
# pylint: disable=too-many-branches
def update_cst(self, target: Constituenta, data: dict) -> dict:
def update_cst(self, target: int, data: dict) -> dict:
''' Update persistent attributes of a given constituenta. Return old values. '''
self.cache.ensure_loaded_terms()
cst = self.cache.by_id.get(target.pk)
cst = self.cache.by_id.get(target)
if cst is None:
raise ValidationError(msg.constituentaNotInRSform(target.alias))
raise ValidationError(msg.constituentaNotInRSform(str(target)))
old_data = {}
term_changed = False
@ -211,13 +211,14 @@ class RSFormCached:
)
return old_data
def delete_cst(self, target: Iterable[Constituenta]) -> None:
def delete_cst(self, target: list[int]) -> None:
''' Delete multiple constituents. '''
mapping = {cst.alias: DELETED_ALIAS for cst in target}
self.cache.ensure_loaded()
self.cache.remove_multi(target)
cst_list = [self.cache.by_id[cst_id] for cst_id in target]
mapping = {cst.alias: DELETED_ALIAS for cst in cst_list}
self.cache.remove_multi(cst_list)
self.apply_mapping(mapping)
Constituenta.objects.filter(pk__in=[cst.pk for cst in target]).delete()
Constituenta.objects.filter(pk__in=target).delete()
RSForm.save_order(self.cache.constituents)
def substitute(self, substitutions: list[tuple[Constituenta, Constituenta]]) -> None:

View File

@ -97,3 +97,23 @@ class TestRSForm(DBTester):
x2.refresh_from_db()
self.assertEqual(x1.order, 1)
self.assertEqual(x2.order, 0)
def test_delete_cst(self):
x1 = self.schema.insert_last('X1')
x2 = self.schema.insert_last('X2')
d1 = self.schema.insert_last(
alias='D1',
definition_formal='X1 = X2',
definition_raw='@{X1|sing}',
term_raw='@{X2|plur}'
)
self.schema.delete_cst([x1])
x2.refresh_from_db()
d1.refresh_from_db()
self.assertEqual(self.schema.constituentsQ().count(), 2)
self.assertEqual(x2.order, 0)
self.assertEqual(d1.order, 1)
self.assertEqual(d1.definition_formal, 'DEL = X2')
self.assertEqual(d1.definition_raw, '@{DEL|sing}')
self.assertEqual(d1.term_raw, '@{X2|plur}')

View File

@ -118,7 +118,7 @@ class TestRSFormCached(DBTester):
term_raw='@{X2|plur}'
)
self.schema.delete_cst([x1])
self.schema.delete_cst([x1.pk])
x2.refresh_from_db()
d1.refresh_from_db()
self.assertEqual(self.schema.constituentsQ().count(), 2)

View File

@ -86,11 +86,13 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
insert_after = None
else:
insert_after = data['insert_after']
schema = m.RSFormCached(item)
with transaction.atomic():
schema = m.RSFormCached(item)
new_cst = schema.create_cst(data, insert_after)
PropagationFacade.after_create_cst(schema, [new_cst])
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_201_CREATED,
data={
@ -117,11 +119,12 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
serializer = s.CstUpdateSerializer(data=request.data, partial=True, context={'schema': item})
serializer.is_valid(raise_exception=True)
cst = cast(m.Constituenta, serializer.validated_data['target'])
schema = m.RSFormCached(item)
data = serializer.validated_data['item_data']
with transaction.atomic():
old_data = schema.update_cst(cst, data)
PropagationFacade.after_update_cst(schema, cst, data, old_data)
schema = m.RSFormCached(item)
old_data = schema.update_cst(cst.pk, data)
PropagationFacade.after_update_cst(schema, cst.pk, data, old_data)
if 'alias' in data and data['alias'] != cst.alias:
cst.refresh_from_db()
changed_type = 'cst_type' in data and cst.cst_type != data['cst_type']
@ -131,9 +134,8 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
cst.cst_type = data['cst_type']
cst.save()
schema.apply_mapping(mapping=mapping, change_aliases=False)
cst.refresh_from_db()
if changed_type:
PropagationFacade.after_change_cst_type(cst)
PropagationFacade.after_change_cst_type(item.pk, cst.pk, cast(m.CstType, cst.cst_type))
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
@ -202,8 +204,8 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
data={f'{cst.pk}': msg.constituentaNoStructure()}
)
schema = m.RSFormCached(item)
with transaction.atomic():
schema = m.RSFormCached(item)
new_cst = schema.produce_structure(cst, cst_parse)
PropagationFacade.after_create_cst(schema, new_cst)
item.save(update_fields=['time_update'])
@ -215,7 +217,6 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
}
)
@extend_schema(
summary='execute substitutions',
tags=['RSForm'],
@ -236,9 +237,10 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
context={'schema': item}
)
serializer.is_valid(raise_exception=True)
schema = m.RSForm(item)
substitutions: list[tuple[m.Constituenta, m.Constituenta]] = []
with transaction.atomic():
schema = m.RSForm(item)
for substitution in serializer.validated_data['substitutions']:
original = cast(m.Constituenta, substitution['original'])
replacement = cast(m.Constituenta, substitution['substitution'])
@ -246,6 +248,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
PropagationFacade.before_substitute(item.pk, substitutions)
schema.substitute(substitutions)
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(item).data
@ -272,14 +275,16 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
)
serializer.is_valid(raise_exception=True)
cst_list: list[m.Constituenta] = serializer.validated_data['items']
schema = m.RSFormCached(item)
with transaction.atomic():
PropagationFacade.before_delete_cst(schema, cst_list)
schema = m.RSForm(item)
PropagationFacade.before_delete_cst(item.pk, [cst.pk for cst in cst_list])
schema.delete_cst(cst_list)
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(schema.model).data
data=s.RSFormParseSerializer(item).data
)
@extend_schema(
@ -302,13 +307,15 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
context={'schema': item}
)
serializer.is_valid(raise_exception=True)
schema = m.RSForm(item)
with transaction.atomic():
schema = m.RSForm(item)
schema.move_cst(
target=serializer.validated_data['items'],
destination=serializer.validated_data['move_to']
)
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(item).data
@ -328,10 +335,12 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
def reset_aliases(self, request: Request, pk) -> HttpResponse:
''' Endpoint: Recreate all aliases based on order. '''
item = self._get_item()
schema = m.RSForm(item)
with transaction.atomic():
schema = m.RSForm(item)
schema.reset_aliases()
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(item).data
@ -351,9 +360,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
def restore_order(self, request: Request, pk) -> HttpResponse:
''' Endpoint: Restore order based on types and Term graph. '''
item = self._get_item()
with transaction.atomic():
m.OrderManager(m.RSFormCached(item)).restore_order()
item.save(update_fields=['time_update'])
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(item).data