R: Refactoring caches pt1
This commit is contained in:
parent
b94e643043
commit
41e2df21ef
|
|
@ -67,7 +67,7 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
def perform_destroy(self, instance: m.LibraryItem) -> None:
|
def perform_destroy(self, instance: m.LibraryItem) -> None:
|
||||||
if instance.item_type == m.LibraryItemType.RSFORM:
|
if instance.item_type == m.LibraryItemType.RSFORM:
|
||||||
PropagationFacade.before_delete_schema(instance)
|
PropagationFacade.before_delete_schema(instance.pk)
|
||||||
super().perform_destroy(instance)
|
super().perform_destroy(instance)
|
||||||
if instance.item_type == m.LibraryItemType.OPERATION_SCHEMA:
|
if instance.item_type == m.LibraryItemType.OPERATION_SCHEMA:
|
||||||
schemas = list(OperationSchema.owned_schemasQ(instance))
|
schemas = list(OperationSchema.owned_schemasQ(instance))
|
||||||
|
|
@ -172,7 +172,7 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
||||||
clone.location = data.get('location', m.LocationHead.USER)
|
clone.location = data.get('location', m.LocationHead.USER)
|
||||||
clone.save()
|
clone.save()
|
||||||
|
|
||||||
RSFormCached(clone).insert_from(item.pk, request.data['items'] if 'items' in request.data else None)
|
RSFormCached(clone.pk).insert_from(item.pk, request.data['items'] if 'items' in request.data else None)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_201_CREATED,
|
status=c.HTTP_201_CREATED,
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,18 @@ class OperationSchema:
|
||||||
return Layout.objects.get(oss_id=itemID)
|
return Layout.objects.get(oss_id=itemID)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_input(oss: LibraryItem, operation: Operation) -> RSFormCached:
|
def create_input(oss_id: int, operation: Operation) -> LibraryItem:
|
||||||
''' Create input RSForm for given Operation. '''
|
''' Create input RSForm for given Operation. '''
|
||||||
schema = RSFormCached.create(
|
oss = LibraryItem.objects.get(pk=oss_id)
|
||||||
owner=oss.owner,
|
schema = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, owner=oss.owner,
|
||||||
alias=operation.alias,
|
alias=operation.alias,
|
||||||
title=operation.title,
|
title=operation.title,
|
||||||
description=operation.description,
|
description=operation.description,
|
||||||
visible=False,
|
visible=False,
|
||||||
access_policy=oss.access_policy,
|
access_policy=oss.access_policy,
|
||||||
location=oss.location
|
location=oss.location)
|
||||||
)
|
Editor.set(schema.pk, oss.getQ_editors().values_list('pk', flat=True))
|
||||||
Editor.set(schema.model.pk, oss.getQ_editors().values_list('pk', flat=True))
|
operation.setQ_result(schema)
|
||||||
operation.setQ_result(schema.model)
|
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
def refresh_from_db(self) -> None:
|
def refresh_from_db(self) -> None:
|
||||||
|
|
@ -132,7 +131,7 @@ class OperationSchema:
|
||||||
if not schemas:
|
if not schemas:
|
||||||
return
|
return
|
||||||
substitutions = operation.getQ_substitutions()
|
substitutions = operation.getQ_substitutions()
|
||||||
receiver = OperationSchema.create_input(self.model, operation)
|
receiver = RSFormCached(OperationSchema.create_input(self.model.pk, operation).pk)
|
||||||
|
|
||||||
parents: dict = {}
|
parents: dict = {}
|
||||||
children: dict = {}
|
children: dict = {}
|
||||||
|
|
@ -149,7 +148,7 @@ class OperationSchema:
|
||||||
translated_substitutions.append((original, replacement))
|
translated_substitutions.append((original, replacement))
|
||||||
receiver.substitute(translated_substitutions)
|
receiver.substitute(translated_substitutions)
|
||||||
|
|
||||||
for cst in Constituenta.objects.filter(schema=receiver.model).order_by('order'):
|
for cst in Constituenta.objects.filter(schema_id=receiver.pk).order_by('order'):
|
||||||
parent = parents.get(cst.pk)
|
parent = parents.get(cst.pk)
|
||||||
assert parent is not None
|
assert parent is not None
|
||||||
Inheritance.objects.create(
|
Inheritance.objects.create(
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ from .utils import CstMapping, CstSubstitution, create_dependant_mapping, extrac
|
||||||
class OperationSchemaCached:
|
class OperationSchemaCached:
|
||||||
''' Operations schema API with caching. '''
|
''' Operations schema API with caching. '''
|
||||||
|
|
||||||
def __init__(self, model: LibraryItem):
|
def __init__(self, item_id: int):
|
||||||
self.model = model
|
self.pk = item_id
|
||||||
self.cache = OssCache(model.pk)
|
self.cache = OssCache(item_id)
|
||||||
self.engine = PropagationEngine(self.cache)
|
self.engine = PropagationEngine(self.cache)
|
||||||
|
|
||||||
def delete_replica(self, target: int, keep_connections: bool = False, keep_constituents: bool = False):
|
def delete_replica(self, target: int, keep_connections: bool = False, keep_constituents: bool = False):
|
||||||
|
|
@ -72,12 +72,12 @@ class OperationSchemaCached:
|
||||||
has_children = bool(self.cache.extend_graph.outputs[target])
|
has_children = bool(self.cache.extend_graph.outputs[target])
|
||||||
old_schema = self.cache.get_schema(operation)
|
old_schema = self.cache.get_schema(operation)
|
||||||
if schema is None and old_schema is None or \
|
if schema is None and old_schema is None or \
|
||||||
(schema is not None and old_schema is not None and schema.pk == old_schema.model.pk):
|
(schema is not None and old_schema is not None and schema.pk == old_schema.pk):
|
||||||
return
|
return
|
||||||
|
|
||||||
if old_schema is not None:
|
if old_schema is not None:
|
||||||
if has_children:
|
if has_children:
|
||||||
self.before_delete_cst(old_schema.model.pk, [cst.pk for cst in old_schema.cache.constituents])
|
self.before_delete_cst(old_schema.pk, [cst.pk for cst in old_schema.cache.constituents])
|
||||||
self.cache.remove_schema(old_schema)
|
self.cache.remove_schema(old_schema)
|
||||||
|
|
||||||
operation.setQ_result(schema)
|
operation.setQ_result(schema)
|
||||||
|
|
@ -88,7 +88,7 @@ class OperationSchemaCached:
|
||||||
operation.save(update_fields=['alias', 'title', 'description'])
|
operation.save(update_fields=['alias', 'title', 'description'])
|
||||||
|
|
||||||
if schema is not None and has_children:
|
if schema is not None and has_children:
|
||||||
rsform = RSFormCached(schema)
|
rsform = RSFormCached(schema.pk)
|
||||||
self.after_create_cst(rsform, list(rsform.constituentsQ().order_by('order')))
|
self.after_create_cst(rsform, list(rsform.constituentsQ().order_by('order')))
|
||||||
|
|
||||||
def set_arguments(self, target: int, arguments: list[Operation]) -> None:
|
def set_arguments(self, target: int, arguments: list[Operation]) -> None:
|
||||||
|
|
@ -172,7 +172,8 @@ class OperationSchemaCached:
|
||||||
if not schemas:
|
if not schemas:
|
||||||
return False
|
return False
|
||||||
substitutions = operation.getQ_substitutions()
|
substitutions = operation.getQ_substitutions()
|
||||||
receiver = OperationSchema.create_input(self.model, self.cache.operation_by_id[operation.pk])
|
new_schema = OperationSchema.create_input(self.pk, self.cache.operation_by_id[operation.pk])
|
||||||
|
receiver = RSFormCached(new_schema.pk)
|
||||||
self.cache.insert_schema(receiver)
|
self.cache.insert_schema(receiver)
|
||||||
|
|
||||||
parents: dict = {}
|
parents: dict = {}
|
||||||
|
|
@ -190,7 +191,7 @@ class OperationSchemaCached:
|
||||||
translated_substitutions.append((original, replacement))
|
translated_substitutions.append((original, replacement))
|
||||||
receiver.substitute(translated_substitutions)
|
receiver.substitute(translated_substitutions)
|
||||||
|
|
||||||
for cst in Constituenta.objects.filter(schema=receiver.model).order_by('order'):
|
for cst in Constituenta.objects.filter(schema_id=receiver.pk).order_by('order'):
|
||||||
parent = parents.get(cst.pk)
|
parent = parents.get(cst.pk)
|
||||||
assert parent is not None
|
assert parent is not None
|
||||||
Inheritance.objects.create(
|
Inheritance.objects.create(
|
||||||
|
|
@ -204,9 +205,8 @@ class OperationSchemaCached:
|
||||||
receiver.resolve_all_text()
|
receiver.resolve_all_text()
|
||||||
|
|
||||||
if self.cache.extend_graph.outputs[operation.pk]:
|
if self.cache.extend_graph.outputs[operation.pk]:
|
||||||
receiver_items = list(Constituenta.objects.filter(schema=receiver.model).order_by('order'))
|
receiver_items = list(Constituenta.objects.filter(schema_id=receiver.pk).order_by('order'))
|
||||||
self.after_create_cst(receiver, receiver_items)
|
self.after_create_cst(receiver, receiver_items)
|
||||||
receiver.model.save(update_fields=['time_update'])
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def relocate_down(self, source: RSFormCached, destination: RSFormCached, items: list[int]):
|
def relocate_down(self, source: RSFormCached, destination: RSFormCached, items: list[int]):
|
||||||
|
|
@ -214,7 +214,7 @@ class OperationSchemaCached:
|
||||||
self.cache.ensure_loaded_subs()
|
self.cache.ensure_loaded_subs()
|
||||||
self.cache.insert_schema(source)
|
self.cache.insert_schema(source)
|
||||||
self.cache.insert_schema(destination)
|
self.cache.insert_schema(destination)
|
||||||
operation = self.cache.get_operation(destination.model.pk)
|
operation = self.cache.get_operation(destination.pk)
|
||||||
self.engine.undo_substitutions_cst(items, operation, destination)
|
self.engine.undo_substitutions_cst(items, operation, destination)
|
||||||
inheritance_to_delete = [item for item in self.cache.inheritance[operation.pk] if item.parent_id in items]
|
inheritance_to_delete = [item for item in self.cache.inheritance[operation.pk] if item.parent_id in items]
|
||||||
for item in inheritance_to_delete:
|
for item in inheritance_to_delete:
|
||||||
|
|
@ -228,7 +228,7 @@ class OperationSchemaCached:
|
||||||
self.cache.insert_schema(source)
|
self.cache.insert_schema(source)
|
||||||
self.cache.insert_schema(destination)
|
self.cache.insert_schema(destination)
|
||||||
|
|
||||||
operation = self.cache.get_operation(source.model.pk)
|
operation = self.cache.get_operation(source.pk)
|
||||||
alias_mapping: dict[str, str] = {}
|
alias_mapping: dict[str, str] = {}
|
||||||
for item in self.cache.inheritance[operation.pk]:
|
for item in self.cache.inheritance[operation.pk]:
|
||||||
if item.parent_id in destination.cache.by_id:
|
if item.parent_id in destination.cache.by_id:
|
||||||
|
|
@ -236,7 +236,7 @@ class OperationSchemaCached:
|
||||||
destination_cst = destination.cache.by_id[item.parent_id]
|
destination_cst = destination.cache.by_id[item.parent_id]
|
||||||
alias_mapping[source_cst.alias] = destination_cst.alias
|
alias_mapping[source_cst.alias] = destination_cst.alias
|
||||||
|
|
||||||
new_items = destination.insert_from(source.model.pk, item_ids, alias_mapping)
|
new_items = destination.insert_from(source.pk, item_ids, alias_mapping)
|
||||||
for (cst, new_cst) in new_items:
|
for (cst, new_cst) in new_items:
|
||||||
new_inheritance = Inheritance.objects.create(
|
new_inheritance = Inheritance.objects.create(
|
||||||
operation=operation,
|
operation=operation,
|
||||||
|
|
@ -246,7 +246,6 @@ class OperationSchemaCached:
|
||||||
self.cache.insert_inheritance(new_inheritance)
|
self.cache.insert_inheritance(new_inheritance)
|
||||||
new_constituents = [item[1] for item in new_items]
|
new_constituents = [item[1] for item in new_items]
|
||||||
self.after_create_cst(destination, new_constituents, exclude=[operation.pk])
|
self.after_create_cst(destination, new_constituents, exclude=[operation.pk])
|
||||||
destination.model.save(update_fields=['time_update'])
|
|
||||||
return new_constituents
|
return new_constituents
|
||||||
|
|
||||||
def after_create_cst(
|
def after_create_cst(
|
||||||
|
|
@ -257,7 +256,7 @@ class OperationSchemaCached:
|
||||||
''' Trigger cascade resolutions when new Constituenta is created. '''
|
''' Trigger cascade resolutions when new Constituenta is created. '''
|
||||||
self.cache.insert_schema(source)
|
self.cache.insert_schema(source)
|
||||||
alias_mapping = create_dependant_mapping(source, cst_list)
|
alias_mapping = create_dependant_mapping(source, cst_list)
|
||||||
operation = self.cache.get_operation(source.model.pk)
|
operation = self.cache.get_operation(source.pk)
|
||||||
self.engine.on_inherit_cst(operation.pk, source, cst_list, alias_mapping, exclude)
|
self.engine.on_inherit_cst(operation.pk, source, cst_list, alias_mapping, exclude)
|
||||||
|
|
||||||
def after_change_cst_type(self, schemaID: int, target: int, new_type: CstType) -> None:
|
def after_change_cst_type(self, schemaID: int, target: int, new_type: CstType) -> None:
|
||||||
|
|
@ -268,7 +267,7 @@ class OperationSchemaCached:
|
||||||
def after_update_cst(self, source: RSFormCached, target: int, 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. '''
|
''' Trigger cascade resolutions when Constituenta data is changed. '''
|
||||||
self.cache.insert_schema(source)
|
self.cache.insert_schema(source)
|
||||||
operation = self.cache.get_operation(source.model.pk)
|
operation = self.cache.get_operation(source.pk)
|
||||||
depend_aliases = extract_data_references(data, old_data)
|
depend_aliases = extract_data_references(data, old_data)
|
||||||
alias_mapping: CstMapping = {}
|
alias_mapping: CstMapping = {}
|
||||||
for alias in depend_aliases:
|
for alias in depend_aliases:
|
||||||
|
|
@ -347,7 +346,7 @@ class OperationSchemaCached:
|
||||||
original_cst = schema.cache.by_id[original_id]
|
original_cst = schema.cache.by_id[original_id]
|
||||||
substitution_cst = schema.cache.by_id[substitution_id]
|
substitution_cst = schema.cache.by_id[substitution_id]
|
||||||
cst_mapping.append((original_cst, substitution_cst))
|
cst_mapping.append((original_cst, substitution_cst))
|
||||||
self.before_substitute(schema.model.pk, cst_mapping)
|
self.before_substitute(schema.pk, cst_mapping)
|
||||||
schema.substitute(cst_mapping)
|
schema.substitute(cst_mapping)
|
||||||
for sub in added:
|
for sub in added:
|
||||||
self.cache.insert_substitution(sub)
|
self.cache.insert_substitution(sub)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class OssCache:
|
||||||
if operation.result_id in self._schema_by_id:
|
if operation.result_id in self._schema_by_id:
|
||||||
return self._schema_by_id[operation.result_id]
|
return self._schema_by_id[operation.result_id]
|
||||||
else:
|
else:
|
||||||
schema = RSFormCached.from_id(operation.result_id)
|
schema = RSFormCached(operation.result_id)
|
||||||
schema.cache.ensure_loaded()
|
schema.cache.ensure_loaded()
|
||||||
self._insert_new(schema)
|
self._insert_new(schema)
|
||||||
return schema
|
return schema
|
||||||
|
|
@ -77,7 +77,7 @@ class OssCache:
|
||||||
if target in self._schema_by_id:
|
if target in self._schema_by_id:
|
||||||
return self._schema_by_id[target]
|
return self._schema_by_id[target]
|
||||||
else:
|
else:
|
||||||
schema = RSFormCached.from_id(target)
|
schema = RSFormCached(target)
|
||||||
schema.cache.ensure_loaded()
|
schema.cache.ensure_loaded()
|
||||||
self._insert_new(schema)
|
self._insert_new(schema)
|
||||||
return schema
|
return schema
|
||||||
|
|
@ -113,7 +113,7 @@ class OssCache:
|
||||||
|
|
||||||
def insert_schema(self, schema: RSFormCached) -> None:
|
def insert_schema(self, schema: RSFormCached) -> None:
|
||||||
''' Insert new schema. '''
|
''' Insert new schema. '''
|
||||||
if not self._schema_by_id.get(schema.model.pk):
|
if not self._schema_by_id.get(schema.pk):
|
||||||
schema.cache.ensure_loaded()
|
schema.cache.ensure_loaded()
|
||||||
self._insert_new(schema)
|
self._insert_new(schema)
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@ class OssCache:
|
||||||
def remove_schema(self, schema: RSFormCached) -> None:
|
def remove_schema(self, schema: RSFormCached) -> None:
|
||||||
''' Remove schema from cache. '''
|
''' Remove schema from cache. '''
|
||||||
self._schemas.remove(schema)
|
self._schemas.remove(schema)
|
||||||
del self._schema_by_id[schema.model.pk]
|
del self._schema_by_id[schema.pk]
|
||||||
|
|
||||||
def remove_operation(self, operation: int) -> None:
|
def remove_operation(self, operation: int) -> None:
|
||||||
''' Remove operation from cache. '''
|
''' Remove operation from cache. '''
|
||||||
|
|
@ -185,4 +185,4 @@ class OssCache:
|
||||||
|
|
||||||
def _insert_new(self, schema: RSFormCached) -> None:
|
def _insert_new(self, schema: RSFormCached) -> None:
|
||||||
self._schemas.append(schema)
|
self._schemas.append(schema)
|
||||||
self._schema_by_id[schema.model.pk] = schema
|
self._schema_by_id[schema.pk] = schema
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,42 @@
|
||||||
''' Models: Change propagation facade - managing all changes in OSS. '''
|
''' Models: Change propagation facade - managing all changes in OSS. '''
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from apps.library.models import LibraryItem, LibraryItemType
|
from apps.library.models import LibraryItem
|
||||||
from apps.rsform.models import Attribution, Constituenta, CstType, RSFormCached
|
from apps.rsform.models import Attribution, Constituenta, CstType, RSFormCached
|
||||||
|
|
||||||
from .OperationSchemaCached import CstSubstitution, OperationSchemaCached
|
from .OperationSchemaCached import CstSubstitution, OperationSchemaCached
|
||||||
|
|
||||||
|
|
||||||
def _get_oss_hosts(schemaID: int) -> list[LibraryItem]:
|
def _get_oss_hosts(schemaID: int) -> list[int]:
|
||||||
''' Get all hosts for LibraryItem. '''
|
''' Get all hosts for schema. '''
|
||||||
return list(LibraryItem.objects.filter(operations__result_id=schemaID).only('pk').distinct())
|
return list(LibraryItem.objects.filter(operations__result_id=schemaID).values_list('pk', flat=True))
|
||||||
|
|
||||||
|
|
||||||
class PropagationFacade:
|
class PropagationFacade:
|
||||||
''' Change propagation API. '''
|
''' Change propagation API. '''
|
||||||
|
|
||||||
|
_oss: dict[int, OperationSchemaCached] = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_oss(schemaID: int) -> OperationSchemaCached:
|
||||||
|
''' Get OperationSchemaCached for schemaID. '''
|
||||||
|
if schemaID not in PropagationFacade._oss:
|
||||||
|
PropagationFacade._oss[schemaID] = OperationSchemaCached(schemaID)
|
||||||
|
return PropagationFacade._oss[schemaID]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def reset_cache() -> None:
|
||||||
|
''' Reset cache. '''
|
||||||
|
PropagationFacade._oss = {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def after_create_cst(source: RSFormCached, new_cst: list[Constituenta],
|
def after_create_cst(source: RSFormCached, new_cst: list[Constituenta],
|
||||||
exclude: Optional[list[int]] = None) -> None:
|
exclude: Optional[list[int]] = None) -> None:
|
||||||
''' Trigger cascade resolutions when new constituenta is created. '''
|
''' Trigger cascade resolutions when new constituenta is created. '''
|
||||||
hosts = _get_oss_hosts(source.model.pk)
|
hosts = _get_oss_hosts(source.pk)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).after_create_cst(source, new_cst)
|
PropagationFacade.get_oss(host).after_create_cst(source, new_cst)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def after_change_cst_type(sourceID: int, target: int, new_type: CstType,
|
def after_change_cst_type(sourceID: int, target: int, new_type: CstType,
|
||||||
|
|
@ -30,8 +44,8 @@ class PropagationFacade:
|
||||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||||
hosts = _get_oss_hosts(sourceID)
|
hosts = _get_oss_hosts(sourceID)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).after_change_cst_type(sourceID, target, new_type)
|
PropagationFacade.get_oss(host).after_change_cst_type(sourceID, target, new_type)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def after_update_cst(
|
def after_update_cst(
|
||||||
|
|
@ -42,10 +56,10 @@ class PropagationFacade:
|
||||||
exclude: Optional[list[int]] = None
|
exclude: Optional[list[int]] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
''' Trigger cascade resolutions when constituenta data is changed. '''
|
''' Trigger cascade resolutions when constituenta data is changed. '''
|
||||||
hosts = _get_oss_hosts(source.model.pk)
|
hosts = _get_oss_hosts(source.pk)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).after_update_cst(source, target, data, old_data)
|
PropagationFacade.get_oss(host).after_update_cst(source, target, data, old_data)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def before_delete_cst(sourceID: int, target: list[int],
|
def before_delete_cst(sourceID: int, target: list[int],
|
||||||
|
|
@ -53,8 +67,8 @@ class PropagationFacade:
|
||||||
''' Trigger cascade resolutions before constituents are deleted. '''
|
''' Trigger cascade resolutions before constituents are deleted. '''
|
||||||
hosts = _get_oss_hosts(sourceID)
|
hosts = _get_oss_hosts(sourceID)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).before_delete_cst(sourceID, target)
|
PropagationFacade.get_oss(host).before_delete_cst(sourceID, target)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def before_substitute(sourceID: int, substitutions: CstSubstitution,
|
def before_substitute(sourceID: int, substitutions: CstSubstitution,
|
||||||
|
|
@ -64,31 +78,31 @@ class PropagationFacade:
|
||||||
return
|
return
|
||||||
hosts = _get_oss_hosts(sourceID)
|
hosts = _get_oss_hosts(sourceID)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).before_substitute(sourceID, substitutions)
|
PropagationFacade.get_oss(host).before_substitute(sourceID, substitutions)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def before_delete_schema(item: LibraryItem, exclude: Optional[list[int]] = None) -> None:
|
def before_delete_schema(target: int, exclude: Optional[list[int]] = None) -> None:
|
||||||
''' Trigger cascade resolutions before schema is deleted. '''
|
''' Trigger cascade resolutions before schema is deleted. '''
|
||||||
if item.item_type != LibraryItemType.RSFORM:
|
hosts = _get_oss_hosts(target)
|
||||||
return
|
|
||||||
hosts = _get_oss_hosts(item.pk)
|
|
||||||
if not hosts:
|
if not hosts:
|
||||||
return
|
return
|
||||||
|
|
||||||
ids = list(Constituenta.objects.filter(schema=item).order_by('order').values_list('pk', flat=True))
|
ids = list(Constituenta.objects.filter(schema_id=target).order_by('order').values_list('pk', flat=True))
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).before_delete_cst(item.pk, ids)
|
PropagationFacade.get_oss(host).before_delete_cst(target, ids)
|
||||||
|
del PropagationFacade._oss[host]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def after_create_attribution(sourceID: int, attributions: list[Attribution],
|
def after_create_attribution(sourceID: int,
|
||||||
|
attributions: list[Attribution],
|
||||||
exclude: Optional[list[int]] = None) -> None:
|
exclude: Optional[list[int]] = None) -> None:
|
||||||
''' Trigger cascade resolutions when Attribution is created. '''
|
''' Trigger cascade resolutions when Attribution is created. '''
|
||||||
hosts = _get_oss_hosts(sourceID)
|
hosts = _get_oss_hosts(sourceID)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).after_create_attribution(sourceID, attributions)
|
PropagationFacade.get_oss(host).after_create_attribution(sourceID, attributions)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def before_delete_attribution(sourceID: int,
|
def before_delete_attribution(sourceID: int,
|
||||||
|
|
@ -97,5 +111,5 @@ class PropagationFacade:
|
||||||
''' Trigger cascade resolutions before Attribution is deleted. '''
|
''' Trigger cascade resolutions before Attribution is deleted. '''
|
||||||
hosts = _get_oss_hosts(sourceID)
|
hosts = _get_oss_hosts(sourceID)
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
if exclude is None or host.pk not in exclude:
|
if exclude is None or host not in exclude:
|
||||||
OperationSchemaCached(host).before_delete_attribution(sourceID, attributions)
|
PropagationFacade.get_oss(host).before_delete_attribution(sourceID, attributions)
|
||||||
|
|
|
||||||
|
|
@ -625,15 +625,6 @@ class RelocateConstituentsSerializer(StrictSerializer):
|
||||||
'items': msg.RelocatingInherited()
|
'items': msg.RelocatingInherited()
|
||||||
})
|
})
|
||||||
|
|
||||||
oss = LibraryItem.objects \
|
|
||||||
.filter(operations__result_id=attrs['destination']) \
|
|
||||||
.filter(operations__result_id=attrs['source']).only('id')
|
|
||||||
if not oss.exists():
|
|
||||||
raise serializers.ValidationError({
|
|
||||||
'destination': msg.schemasNotConnected()
|
|
||||||
})
|
|
||||||
attrs['oss'] = oss[0].pk
|
|
||||||
|
|
||||||
if Argument.objects.filter(
|
if Argument.objects.filter(
|
||||||
operation__result_id=attrs['destination'],
|
operation__result_id=attrs['destination'],
|
||||||
argument__result_id=attrs['source']
|
argument__result_id=attrs['source']
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
''' Testing API: Change attributes of OSS and RSForms. '''
|
''' Testing API: Change attributes of OSS and RSForms. '''
|
||||||
from apps.library.models import AccessPolicy, Editor, LibraryItem, LocationHead
|
from apps.library.models import AccessPolicy, Editor, LibraryItem, LocationHead
|
||||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import RSForm
|
from apps.rsform.models import RSForm
|
||||||
from apps.users.models import User
|
from apps.users.models import User
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
@ -11,6 +11,7 @@ class TestChangeAttributes(EndpointTester):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.user3 = User.objects.create(
|
self.user3 = User.objects.create(
|
||||||
username='UserTest3',
|
username='UserTest3',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
''' Testing API: Change constituents in OSS. '''
|
''' Testing API: Change constituents in OSS. '''
|
||||||
|
|
||||||
from apps.oss.models import OperationSchema, OperationType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import Attribution, Constituenta, CstType, RSForm
|
from apps.rsform.models import Attribution, Constituenta, CstType, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ class TestChangeConstituents(EndpointTester):
|
||||||
''' Testing Constituents change propagation in OSS. '''
|
''' Testing Constituents change propagation in OSS. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(
|
self.owned = OperationSchema.create(
|
||||||
title='Test',
|
title='Test',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
''' Testing API: Change substitutions in OSS. '''
|
''' Testing API: Change substitutions in OSS. '''
|
||||||
|
|
||||||
from apps.oss.models import OperationSchema, OperationType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import Constituenta, CstType, RSForm
|
from apps.rsform.models import Constituenta, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ class TestChangeOperations(EndpointTester):
|
||||||
''' Testing Operations change propagation in OSS. '''
|
''' Testing Operations change propagation in OSS. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(
|
self.owned = OperationSchema.create(
|
||||||
title='Test',
|
title='Test',
|
||||||
|
|
@ -388,7 +389,7 @@ class TestChangeOperations(EndpointTester):
|
||||||
self.assertEqual(self.ks5.constituentsQ().count(), 8)
|
self.assertEqual(self.ks5.constituentsQ().count(), 8)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
@decl_endpoint('/api/oss/{item}/relocate-constituents', method='post')
|
||||||
def test_relocate_constituents_up(self):
|
def test_relocate_constituents_up(self):
|
||||||
ks1_old_count = self.ks1.constituentsQ().count()
|
ks1_old_count = self.ks1.constituentsQ().count()
|
||||||
ks4_old_count = self.ks4.constituentsQ().count()
|
ks4_old_count = self.ks4.constituentsQ().count()
|
||||||
|
|
@ -408,7 +409,7 @@ class TestChangeOperations(EndpointTester):
|
||||||
'items': [ks6A1.pk]
|
'items': [ks6A1.pk]
|
||||||
}
|
}
|
||||||
|
|
||||||
self.executeOK(data)
|
self.executeOK(data, item=self.owned_id)
|
||||||
ks6.model.refresh_from_db()
|
ks6.model.refresh_from_db()
|
||||||
self.ks1.model.refresh_from_db()
|
self.ks1.model.refresh_from_db()
|
||||||
self.ks4.model.refresh_from_db()
|
self.ks4.model.refresh_from_db()
|
||||||
|
|
@ -418,7 +419,7 @@ class TestChangeOperations(EndpointTester):
|
||||||
self.assertEqual(self.ks4.constituentsQ().count(), ks4_old_count + 1)
|
self.assertEqual(self.ks4.constituentsQ().count(), ks4_old_count + 1)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
@decl_endpoint('/api/oss/{item}/relocate-constituents', method='post')
|
||||||
def test_relocate_constituents_down(self):
|
def test_relocate_constituents_down(self):
|
||||||
ks1_old_count = self.ks1.constituentsQ().count()
|
ks1_old_count = self.ks1.constituentsQ().count()
|
||||||
ks4_old_count = self.ks4.constituentsQ().count()
|
ks4_old_count = self.ks4.constituentsQ().count()
|
||||||
|
|
@ -438,7 +439,7 @@ class TestChangeOperations(EndpointTester):
|
||||||
'items': [self.ks1X2.pk]
|
'items': [self.ks1X2.pk]
|
||||||
}
|
}
|
||||||
|
|
||||||
self.executeOK(data)
|
self.executeOK(data, item=self.owned_id)
|
||||||
ks6.model.refresh_from_db()
|
ks6.model.refresh_from_db()
|
||||||
self.ks1.model.refresh_from_db()
|
self.ks1.model.refresh_from_db()
|
||||||
self.ks4.model.refresh_from_db()
|
self.ks4.model.refresh_from_db()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
''' Testing API: Propagate changes through references in OSS. '''
|
''' Testing API: Propagate changes through references in OSS. '''
|
||||||
|
|
||||||
from apps.oss.models import Inheritance, OperationSchema, OperationType
|
from apps.oss.models import Inheritance, OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import Constituenta, CstType, RSForm
|
from apps.rsform.models import Constituenta, CstType, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ class ReferencePropagationTestCase(EndpointTester):
|
||||||
''' Test propagation through references in OSS. '''
|
''' Test propagation through references in OSS. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
self.owned = OperationSchema.create(
|
self.owned = OperationSchema.create(
|
||||||
|
|
@ -163,7 +164,7 @@ class ReferencePropagationTestCase(EndpointTester):
|
||||||
@decl_endpoint('/api/rsforms/{schema}/delete-multiple-cst', method='patch')
|
@decl_endpoint('/api/rsforms/{schema}/delete-multiple-cst', method='patch')
|
||||||
def test_delete_constituenta(self):
|
def test_delete_constituenta(self):
|
||||||
data = {'items': [self.ks1X1.pk]}
|
data = {'items': [self.ks1X1.pk]}
|
||||||
response = self.executeOK(data, schema=self.ks1.model.pk)
|
self.executeOK(data, schema=self.ks1.model.pk)
|
||||||
self.ks4D2.refresh_from_db()
|
self.ks4D2.refresh_from_db()
|
||||||
self.ks5D4.refresh_from_db()
|
self.ks5D4.refresh_from_db()
|
||||||
self.ks6D2.refresh_from_db()
|
self.ks6D2.refresh_from_db()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
''' Testing API: Change substitutions in OSS. '''
|
''' Testing API: Change substitutions in OSS. '''
|
||||||
|
|
||||||
from apps.oss.models import OperationSchema, OperationType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import Constituenta, CstType, RSForm
|
from apps.rsform.models import Constituenta, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@ class TestChangeSubstitutions(EndpointTester):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(
|
self.owned = OperationSchema.create(
|
||||||
title='Test',
|
title='Test',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
''' Testing API: Operation Schema - blocks manipulation. '''
|
''' Testing API: Operation Schema - blocks manipulation. '''
|
||||||
from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -9,6 +8,7 @@ class TestOssBlocks(EndpointTester):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
||||||
self.owned_id = self.owned.model.pk
|
self.owned_id = self.owned.model.pk
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
''' Testing API: Operation Schema - operations manipulation. '''
|
''' Testing API: Operation Schema - operations manipulation. '''
|
||||||
from apps.library.models import Editor, LibraryItem
|
from apps.library.models import Editor, LibraryItem
|
||||||
from apps.oss.models import Argument, Operation, OperationSchema, OperationType, Replica
|
from apps.oss.models import (
|
||||||
|
Argument,
|
||||||
|
Operation,
|
||||||
|
OperationSchema,
|
||||||
|
OperationType,
|
||||||
|
PropagationFacade,
|
||||||
|
Replica
|
||||||
|
)
|
||||||
from apps.rsform.models import Attribution, RSForm
|
from apps.rsform.models import Attribution, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
@ -10,6 +17,7 @@ class TestOssOperations(EndpointTester):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
||||||
self.owned_id = self.owned.model.pk
|
self.owned_id = self.owned.model.pk
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
''' Testing API: Operation Schema. '''
|
''' Testing API: Operation Schema. '''
|
||||||
from apps.library.models import AccessPolicy, LibraryItemType
|
from apps.library.models import AccessPolicy, LibraryItemType
|
||||||
from apps.oss.models import OperationSchema, OperationType
|
from apps.oss.models import OperationSchema, OperationType, PropagationFacade
|
||||||
from apps.rsform.models import Constituenta, RSForm
|
from apps.rsform.models import Constituenta, RSForm
|
||||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
@ -9,6 +9,7 @@ class TestOssViewset(EndpointTester):
|
||||||
''' Testing OSS view. '''
|
''' Testing OSS view. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
PropagationFacade.reset_cache()
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
self.owned = OperationSchema.create(title='Test', alias='T1', owner=self.user)
|
||||||
self.owned_id = self.owned.model.pk
|
self.owned_id = self.owned.model.pk
|
||||||
|
|
@ -220,8 +221,9 @@ class TestOssViewset(EndpointTester):
|
||||||
self.executeBadData(data)
|
self.executeBadData(data)
|
||||||
|
|
||||||
|
|
||||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
@decl_endpoint('/api/oss/{item}/relocate-constituents', method='post')
|
||||||
def test_relocate_constituents(self):
|
def test_relocate_constituents(self):
|
||||||
|
self.set_params(item=self.owned_id)
|
||||||
self.populateData()
|
self.populateData()
|
||||||
self.ks1X2 = self.ks1.insert_last('X2', convention='test')
|
self.ks1X2 = self.ks1.insert_last('X2', convention='test')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from rest_framework.response import Response
|
||||||
|
|
||||||
from apps.library.models import LibraryItem, LibraryItemType
|
from apps.library.models import LibraryItem, LibraryItemType
|
||||||
from apps.library.serializers import LibraryItemSerializer
|
from apps.library.serializers import LibraryItemSerializer
|
||||||
|
from apps.oss.models import PropagationFacade
|
||||||
from apps.rsform.models import Constituenta, RSFormCached
|
from apps.rsform.models import Constituenta, RSFormCached
|
||||||
from apps.rsform.serializers import CstTargetSerializer
|
from apps.rsform.serializers import CstTargetSerializer
|
||||||
from shared import messages as msg
|
from shared import messages as msg
|
||||||
|
|
@ -291,7 +292,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
'height': position['height']
|
'height': position['height']
|
||||||
})
|
})
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
m.OperationSchema.create_input(item, new_operation)
|
m.OperationSchema.create_input(item.pk, new_operation)
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
|
@ -420,7 +421,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
schema_clone.access_policy = item.access_policy
|
schema_clone.access_policy = item.access_policy
|
||||||
schema_clone.location = item.location
|
schema_clone.location = item.location
|
||||||
schema_clone.save()
|
schema_clone.save()
|
||||||
RSFormCached(schema_clone).insert_from(prototype.pk)
|
RSFormCached(schema_clone.pk).insert_from(prototype.pk)
|
||||||
|
|
||||||
new_operation.result = schema_clone
|
new_operation.result = schema_clone
|
||||||
new_operation.save(update_fields=["result"])
|
new_operation.save(update_fields=["result"])
|
||||||
|
|
@ -544,7 +545,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
|
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
if 'layout' in serializer.validated_data:
|
if 'layout' in serializer.validated_data:
|
||||||
layout = serializer.validated_data['layout']
|
layout = serializer.validated_data['layout']
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
|
|
@ -599,12 +600,12 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
|
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents'])
|
oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents'])
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
if old_schema is not None:
|
if old_schema is not None:
|
||||||
if serializer.validated_data['delete_schema']:
|
if serializer.validated_data['delete_schema']:
|
||||||
m.PropagationFacade.before_delete_schema(old_schema)
|
m.PropagationFacade.before_delete_schema(old_schema.pk)
|
||||||
old_schema.delete()
|
old_schema.delete()
|
||||||
elif old_schema.is_synced(item):
|
elif old_schema.is_synced(item):
|
||||||
old_schema.visible = True
|
old_schema.visible = True
|
||||||
|
|
@ -640,7 +641,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
|
layout = [x for x in layout if x['nodeID'] != 'o' + str(operation.pk)]
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
oss.delete_replica(operation.pk, keep_connections, keep_constituents)
|
oss.delete_replica(operation.pk, keep_connections, keep_constituents)
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
@ -680,13 +681,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
schema = m.OperationSchema.create_input(item, operation)
|
schema = m.OperationSchema.create_input(item.pk, operation)
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data={
|
data={
|
||||||
'new_schema': LibraryItemSerializer(schema.model).data,
|
'new_schema': LibraryItemSerializer(schema).data,
|
||||||
'oss': s.OperationSchemaSerializer(item).data
|
'oss': s.OperationSchemaSerializer(item).data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -726,7 +727,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
old_schema = target_operation.result
|
old_schema = target_operation.result
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
if old_schema is not None:
|
if old_schema is not None:
|
||||||
if old_schema.is_synced(item):
|
if old_schema.is_synced(item):
|
||||||
old_schema.visible = True
|
old_schema.visible = True
|
||||||
|
|
@ -769,7 +770,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
layout = serializer.validated_data['layout']
|
layout = serializer.validated_data['layout']
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
oss.execute_operation(operation)
|
oss.execute_operation(operation)
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
@ -823,24 +824,26 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@action(detail=False, methods=['post'], url_path='relocate-constituents')
|
@action(detail=True, methods=['post'], url_path='relocate-constituents')
|
||||||
def relocate_constituents(self, request: Request) -> Response:
|
def relocate_constituents(self, request: Request, pk) -> Response:
|
||||||
''' Relocate constituents from one schema to another. '''
|
''' Relocate constituents from one schema to another. '''
|
||||||
|
item = self._get_item()
|
||||||
serializer = s.RelocateConstituentsSerializer(data=request.data)
|
serializer = s.RelocateConstituentsSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
data = serializer.validated_data
|
data = serializer.validated_data
|
||||||
ids = [cst.pk for cst in data['items']]
|
ids = [cst.pk for cst in data['items']]
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(LibraryItem.objects.get(pk=data['oss']))
|
oss = PropagationFacade.get_oss(item.pk)
|
||||||
source = RSFormCached(LibraryItem.objects.get(pk=data['source']))
|
source = RSFormCached(data['source'])
|
||||||
destination = RSFormCached(LibraryItem.objects.get(pk=data['destination']))
|
destination = RSFormCached(data['destination'])
|
||||||
if data['move_down']:
|
if data['move_down']:
|
||||||
oss.relocate_down(source, destination, ids)
|
oss.relocate_down(source, destination, ids)
|
||||||
m.PropagationFacade.before_delete_cst(data['source'], ids)
|
m.PropagationFacade.before_delete_cst(source.pk, ids)
|
||||||
source.delete_cst(ids)
|
source.delete_cst(ids)
|
||||||
else:
|
else:
|
||||||
new_items = oss.relocate_up(source, destination, ids)
|
new_items = oss.relocate_up(source, destination, ids)
|
||||||
m.PropagationFacade.after_create_cst(destination, new_items, exclude=[oss.model.pk])
|
m.PropagationFacade.after_create_cst(destination, new_items, exclude=[oss.pk])
|
||||||
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(status=c.HTTP_200_OK)
|
return Response(status=c.HTTP_200_OK)
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,15 @@ from .RSForm import DELETED_ALIAS, RSForm
|
||||||
class RSFormCached:
|
class RSFormCached:
|
||||||
''' RSForm cached. Caching allows to avoid querying for each method call. '''
|
''' RSForm cached. Caching allows to avoid querying for each method call. '''
|
||||||
|
|
||||||
def __init__(self, model: LibraryItem):
|
def __init__(self, item_id: int):
|
||||||
self.model = model
|
self.pk = item_id
|
||||||
self.cache: _RSFormCache = _RSFormCache(self)
|
self.cache: _RSFormCache = _RSFormCache(self)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(**kwargs) -> 'RSFormCached':
|
def create(**kwargs) -> 'RSFormCached':
|
||||||
''' Create LibraryItem via RSForm. '''
|
''' Create LibraryItem via RSForm. '''
|
||||||
model = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, **kwargs)
|
model = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, **kwargs)
|
||||||
return RSFormCached(model)
|
return RSFormCached(model.pk)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_id(pk: int) -> 'RSFormCached':
|
|
||||||
''' Get LibraryItem by pk. '''
|
|
||||||
model = LibraryItem.objects.get(pk=pk)
|
|
||||||
return RSFormCached(model)
|
|
||||||
|
|
||||||
def get_dependant(self, target: Iterable[int]) -> set[int]:
|
def get_dependant(self, target: Iterable[int]) -> set[int]:
|
||||||
''' Get list of constituents depending on target (only 1st degree). '''
|
''' Get list of constituents depending on target (only 1st degree). '''
|
||||||
|
|
@ -51,7 +45,7 @@ class RSFormCached:
|
||||||
|
|
||||||
def constituentsQ(self) -> QuerySet[Constituenta]:
|
def constituentsQ(self) -> QuerySet[Constituenta]:
|
||||||
''' Get QuerySet containing all constituents of current RSForm. '''
|
''' Get QuerySet containing all constituents of current RSForm. '''
|
||||||
return Constituenta.objects.filter(schema=self.model)
|
return Constituenta.objects.filter(schema_id=self.pk)
|
||||||
|
|
||||||
def insert_last(
|
def insert_last(
|
||||||
self,
|
self,
|
||||||
|
|
@ -62,9 +56,9 @@ class RSFormCached:
|
||||||
''' Insert new constituenta at last position. '''
|
''' Insert new constituenta at last position. '''
|
||||||
if cst_type is None:
|
if cst_type is None:
|
||||||
cst_type = guess_type(alias)
|
cst_type = guess_type(alias)
|
||||||
position = Constituenta.objects.filter(schema=self.model).count()
|
position = Constituenta.objects.filter(schema_id=self.pk).count()
|
||||||
result = Constituenta.objects.create(
|
result = Constituenta.objects.create(
|
||||||
schema=self.model,
|
schema_id=self.pk,
|
||||||
order=position,
|
order=position,
|
||||||
alias=alias,
|
alias=alias,
|
||||||
cst_type=cst_type,
|
cst_type=cst_type,
|
||||||
|
|
@ -83,7 +77,7 @@ class RSFormCached:
|
||||||
RSForm.shift_positions(position, 1, self.cache.constituents)
|
RSForm.shift_positions(position, 1, self.cache.constituents)
|
||||||
|
|
||||||
result = Constituenta.objects.create(
|
result = Constituenta.objects.create(
|
||||||
schema=self.model,
|
schema_id=self.pk,
|
||||||
order=position,
|
order=position,
|
||||||
alias=data['alias'],
|
alias=data['alias'],
|
||||||
cst_type=data['cst_type'],
|
cst_type=data['cst_type'],
|
||||||
|
|
@ -160,7 +154,7 @@ class RSFormCached:
|
||||||
new_constituents = deepcopy(items)
|
new_constituents = deepcopy(items)
|
||||||
for cst in new_constituents:
|
for cst in new_constituents:
|
||||||
cst.pk = None
|
cst.pk = None
|
||||||
cst.schema = self.model
|
cst.schema_id = self.pk
|
||||||
cst.order = position
|
cst.order = position
|
||||||
if mapping_alias:
|
if mapping_alias:
|
||||||
cst.alias = mapping_alias[cst.alias]
|
cst.alias = mapping_alias[cst.alias]
|
||||||
|
|
@ -263,7 +257,7 @@ class RSFormCached:
|
||||||
deleted.append(original)
|
deleted.append(original)
|
||||||
replacements.append(substitution.pk)
|
replacements.append(substitution.pk)
|
||||||
|
|
||||||
attributions = list(Attribution.objects.filter(container__schema=self.model))
|
attributions = list(Attribution.objects.filter(container__schema_id=self.pk))
|
||||||
if attributions:
|
if attributions:
|
||||||
orig_to_sub = {original.pk: substitution.pk for original, substitution in substitutions}
|
orig_to_sub = {original.pk: substitution.pk for original, substitution in substitutions}
|
||||||
orig_pks = set(orig_to_sub.keys())
|
orig_pks = set(orig_to_sub.keys())
|
||||||
|
|
@ -374,7 +368,7 @@ class RSFormCached:
|
||||||
prefix = get_type_prefix(cst_type)
|
prefix = get_type_prefix(cst_type)
|
||||||
for text in expressions:
|
for text in expressions:
|
||||||
new_item = Constituenta.objects.create(
|
new_item = Constituenta.objects.create(
|
||||||
schema=self.model,
|
schema_id=self.pk,
|
||||||
order=position,
|
order=position,
|
||||||
alias=f'{prefix}{free_index}',
|
alias=f'{prefix}{free_index}',
|
||||||
definition_formal=text,
|
definition_formal=text,
|
||||||
|
|
@ -392,7 +386,7 @@ class RSFormCached:
|
||||||
cst_list: Iterable[Constituenta] = []
|
cst_list: Iterable[Constituenta] = []
|
||||||
if not self.cache.is_loaded:
|
if not self.cache.is_loaded:
|
||||||
cst_list = Constituenta.objects \
|
cst_list = Constituenta.objects \
|
||||||
.filter(schema=self.model, cst_type=cst_type) \
|
.filter(schema_id=self.pk, cst_type=cst_type) \
|
||||||
.only('alias')
|
.only('alias')
|
||||||
else:
|
else:
|
||||||
cst_list = [cst for cst in self.cache.constituents if cst.cst_type == cst_type]
|
cst_list = [cst for cst in self.cache.constituents if cst.cst_type == cst_type]
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
result['description'] = data.get('description', '')
|
result['description'] = data.get('description', '')
|
||||||
if 'id' in data:
|
if 'id' in data:
|
||||||
result['id'] = data['id']
|
result['id'] = data['id']
|
||||||
self.instance = RSFormCached.from_id(result['id'])
|
self.instance = RSFormCached(result['id'])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def validate(self, attrs: dict):
|
def validate(self, attrs: dict):
|
||||||
|
|
@ -151,7 +151,7 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
for cst_data in validated_data['items']:
|
for cst_data in validated_data['items']:
|
||||||
cst = Constituenta(
|
cst = Constituenta(
|
||||||
alias=cst_data['alias'],
|
alias=cst_data['alias'],
|
||||||
schema=self.instance.model,
|
schema_id=self.instance.pk,
|
||||||
order=order,
|
order=order,
|
||||||
cst_type=cst_data['cstType'],
|
cst_type=cst_data['cstType'],
|
||||||
)
|
)
|
||||||
|
|
@ -163,12 +163,13 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def update(self, instance: RSFormCached, validated_data) -> RSFormCached:
|
def update(self, instance: RSFormCached, validated_data) -> RSFormCached:
|
||||||
|
model = LibraryItem.objects.get(pk=instance.pk)
|
||||||
if 'alias' in validated_data:
|
if 'alias' in validated_data:
|
||||||
instance.model.alias = validated_data['alias']
|
model.alias = validated_data['alias']
|
||||||
if 'title' in validated_data:
|
if 'title' in validated_data:
|
||||||
instance.model.title = validated_data['title']
|
model.title = validated_data['title']
|
||||||
if 'description' in validated_data:
|
if 'description' in validated_data:
|
||||||
instance.model.description = validated_data['description']
|
model.description = validated_data['description']
|
||||||
|
|
||||||
order = 0
|
order = 0
|
||||||
prev_constituents = instance.constituentsQ()
|
prev_constituents = instance.constituentsQ()
|
||||||
|
|
@ -185,7 +186,7 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
else:
|
else:
|
||||||
cst = Constituenta(
|
cst = Constituenta(
|
||||||
alias=cst_data['alias'],
|
alias=cst_data['alias'],
|
||||||
schema=instance.model,
|
schema_id=instance.pk,
|
||||||
order=order,
|
order=order,
|
||||||
cst_type=cst_data['cstType'],
|
cst_type=cst_data['cstType'],
|
||||||
)
|
)
|
||||||
|
|
@ -199,7 +200,7 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
prev_cst.delete()
|
prev_cst.delete()
|
||||||
|
|
||||||
instance.resolve_all_text()
|
instance.resolve_all_text()
|
||||||
instance.model.save()
|
model.save()
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
insert_after = data['insert_after']
|
insert_after = data['insert_after']
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
schema = m.RSFormCached(item)
|
schema = m.RSFormCached(item.pk)
|
||||||
new_cst = schema.create_cst(data, insert_after)
|
new_cst = schema.create_cst(data, insert_after)
|
||||||
PropagationFacade.after_create_cst(schema, [new_cst])
|
PropagationFacade.after_create_cst(schema, [new_cst])
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
@ -125,7 +125,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():
|
||||||
schema = m.RSFormCached(item)
|
schema = m.RSFormCached(item.pk)
|
||||||
old_data = schema.update_cst(cst.pk, data)
|
old_data = schema.update_cst(cst.pk, data)
|
||||||
PropagationFacade.after_update_cst(schema, cst.pk, data, old_data)
|
PropagationFacade.after_update_cst(schema, cst.pk, data, old_data)
|
||||||
if 'alias' in data and data['alias'] != cst.alias:
|
if 'alias' in data and data['alias'] != cst.alias:
|
||||||
|
|
@ -208,7 +208,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
)
|
)
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
schema = m.RSFormCached(item)
|
schema = m.RSFormCached(item.pk)
|
||||||
new_cst = schema.produce_structure(cst, cst_parse)
|
new_cst = schema.produce_structure(cst, cst_parse)
|
||||||
PropagationFacade.after_create_cst(schema, new_cst)
|
PropagationFacade.after_create_cst(schema, new_cst)
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
@ -456,7 +456,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
item = self._get_item()
|
item = self._get_item()
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
m.OrderManager(m.RSFormCached(item)).restore_order()
|
m.OrderManager(m.RSFormCached(item.pk)).restore_order()
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
|
@ -731,7 +731,8 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
||||||
serializer = s.InlineSynthesisSerializer(data=request.data, context={'user': request.user})
|
serializer = s.InlineSynthesisSerializer(data=request.data, context={'user': request.user})
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
receiver = m.RSFormCached(serializer.validated_data['receiver'])
|
item = cast(LibraryItem, serializer.validated_data['receiver'])
|
||||||
|
receiver = m.RSFormCached(item.pk)
|
||||||
target_cst = cast(list[m.Constituenta], serializer.validated_data['items'])
|
target_cst = cast(list[m.Constituenta], serializer.validated_data['items'])
|
||||||
source = cast(LibraryItem, serializer.validated_data['source'])
|
source = cast(LibraryItem, serializer.validated_data['source'])
|
||||||
target_ids = [item.pk for item in target_cst] if target_cst else None
|
target_ids = [item.pk for item in target_cst] if target_cst else None
|
||||||
|
|
@ -752,11 +753,11 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
||||||
replacement = mapping_ids[replacement.pk]
|
replacement = mapping_ids[replacement.pk]
|
||||||
substitutions.append((original, replacement))
|
substitutions.append((original, replacement))
|
||||||
|
|
||||||
PropagationFacade.before_substitute(receiver.model.pk, substitutions)
|
PropagationFacade.before_substitute(receiver.pk, substitutions)
|
||||||
receiver.substitute(substitutions)
|
receiver.substitute(substitutions)
|
||||||
receiver.model.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
data=s.RSFormParseSerializer(receiver.model).data
|
data=s.RSFormParseSerializer(item).data
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -215,9 +215,9 @@ export const ossApi = {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
relocateConstituents: (data: IRelocateConstituentsDTO) =>
|
relocateConstituents: ({ itemID, data }: { itemID: number; data: IRelocateConstituentsDTO }) =>
|
||||||
axiosPost<IRelocateConstituentsDTO>({
|
axiosPost<IRelocateConstituentsDTO>({
|
||||||
endpoint: `/api/oss/relocate-constituents`,
|
endpoint: `/api/oss/${itemID}/relocate-constituents`,
|
||||||
request: {
|
request: {
|
||||||
data: data,
|
data: data,
|
||||||
successMessage: infoMsg.changesSaved
|
successMessage: infoMsg.changesSaved
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,6 @@ export const useRelocateConstituents = () => {
|
||||||
onError: () => client.invalidateQueries()
|
onError: () => client.invalidateQueries()
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
relocateConstituents: (data: IRelocateConstituentsDTO) => mutation.mutateAsync(data)
|
relocateConstituents: (data: { itemID: number; data: IRelocateConstituentsDTO }) => mutation.mutateAsync(data)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -106,13 +106,13 @@ export function DlgRelocateConstituents() {
|
||||||
function onSubmit(data: IRelocateConstituentsDTO) {
|
function onSubmit(data: IRelocateConstituentsDTO) {
|
||||||
data.items = moveTarget;
|
data.items = moveTarget;
|
||||||
if (!layout || JSON.stringify(layout) === JSON.stringify(oss.layout)) {
|
if (!layout || JSON.stringify(layout) === JSON.stringify(oss.layout)) {
|
||||||
return relocateConstituents(data);
|
return relocateConstituents({ itemID: oss.id, data: data });
|
||||||
} else {
|
} else {
|
||||||
return updatePositions({
|
return updatePositions({
|
||||||
isSilent: true,
|
isSilent: true,
|
||||||
itemID: oss.id,
|
itemID: oss.id,
|
||||||
data: layout
|
data: layout
|
||||||
}).then(() => relocateConstituents(data));
|
}).then(() => relocateConstituents({ itemID: oss.id, data: data }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user