ConceptPortal-public/rsconcept/backend/apps/oss/models/OperationSchema.py

165 lines
5.9 KiB
Python
Raw Normal View History

2024-07-19 19:29:27 +03:00
''' Models: OSS API. '''
2025-08-03 11:40:22 +03:00
# pylint: disable=duplicate-code
2024-07-19 19:29:27 +03:00
from django.db.models import QuerySet
2024-07-19 19:29:27 +03:00
from apps.library.models import Editor, LibraryItem, LibraryItemType
2025-08-05 15:27:52 +03:00
from apps.rsform.models import Constituenta, OrderManager, RSFormCached
2024-07-19 19:29:27 +03:00
from .Argument import Argument
2025-04-14 23:10:19 +03:00
from .Block import Block
from .Inheritance import Inheritance
2025-04-06 15:49:43 +03:00
from .Layout import Layout
from .Operation import Operation, OperationType
from .Replica import Replica
from .Substitution import Substitution
2024-07-19 19:29:27 +03:00
class OperationSchema:
2025-08-03 11:40:22 +03:00
''' Operations schema API wrapper. No caching, propagation and minimal side effects. '''
2024-07-19 19:29:27 +03:00
def __init__(self, model: LibraryItem):
self.model = model
2024-07-19 19:29:27 +03:00
@staticmethod
def create(**kwargs) -> 'OperationSchema':
''' Create LibraryItem via OperationSchema. '''
model = LibraryItem.objects.create(item_type=LibraryItemType.OPERATION_SCHEMA, **kwargs)
2025-06-11 16:39:12 +03:00
Layout.objects.create(oss=model, data=[])
return OperationSchema(model)
2024-07-22 21:20:51 +03:00
2025-08-03 11:40:22 +03:00
@staticmethod
def owned_schemasQ(item: LibraryItem) -> QuerySet[LibraryItem]:
''' Get QuerySet containing all result schemas owned by current OSS. '''
return LibraryItem.objects.filter(
2025-08-03 11:40:22 +03:00
producer__oss=item,
owner_id=item.owner_id,
location=item.location
)
2025-08-03 11:40:22 +03:00
@staticmethod
def layoutQ(itemID: int) -> Layout:
''' OSS layout. '''
return Layout.objects.get(oss_id=itemID)
2025-08-05 14:26:56 +03:00
@staticmethod
def create_input(oss: LibraryItem, operation: Operation) -> RSFormCached:
''' Create input RSForm for given Operation. '''
schema = RSFormCached.create(
owner=oss.owner,
alias=operation.alias,
title=operation.title,
description=operation.description,
visible=False,
access_policy=oss.access_policy,
location=oss.location
)
Editor.set(schema.model.pk, oss.getQ_editors().values_list('pk', flat=True))
operation.setQ_result(schema.model)
return schema
2025-08-03 11:40:22 +03:00
def refresh_from_db(self) -> None:
''' Model wrapper. '''
self.model.refresh_from_db()
2024-07-19 19:29:27 +03:00
def create_operation(self, **kwargs) -> Operation:
''' Create Operation. '''
result = Operation.objects.create(oss=self.model, **kwargs)
2024-07-19 19:29:27 +03:00
return result
def create_replica(self, target: Operation) -> Operation:
''' Create Replica Operation. '''
result = Operation.objects.create(
oss=self.model,
operation_type=OperationType.REPLICA,
result=target.result,
parent=target.parent
)
Replica.objects.create(replica=result, original=target)
return result
2025-04-14 23:10:19 +03:00
def create_block(self, **kwargs) -> Block:
''' Create Block. '''
2025-04-14 23:10:19 +03:00
result = Block.objects.create(oss=self.model, **kwargs)
return result
def delete_block(self, target: Block):
''' Delete Block. '''
new_parent = target.parent
if new_parent is not None:
for block in Block.objects.filter(parent=target):
if block != new_parent:
block.parent = new_parent
block.save(update_fields=['parent'])
for operation in Operation.objects.filter(parent=target):
operation.parent = new_parent
operation.save(update_fields=['parent'])
target.delete()
2025-08-03 11:40:22 +03:00
def set_arguments(self, target: int, arguments: list[Operation]) -> None:
''' Set arguments of target Operation. '''
Argument.objects.filter(operation_id=target).delete()
order = 0
for arg in arguments:
Argument.objects.create(
operation_id=target,
argument=arg,
order=order
)
order += 1
def set_substitutions(self, target: int, substitutes: list[dict]) -> None:
''' Set Substitutions for target Operation. '''
Substitution.objects.filter(operation_id=target).delete()
for sub_item in substitutes:
Substitution.objects.create(
operation_id=target,
original=sub_item['original'],
substitution=sub_item['substitution']
)
def execute_operation(self, operation: Operation) -> None:
''' Execute target Operation. '''
2025-08-03 11:40:22 +03:00
schemas: list[int] = [
arg.argument.result_id
for arg in Argument.objects
.filter(operation=operation)
.select_related('argument')
.only('argument__result_id')
.order_by('order')
if arg.argument.result_id is not None
]
2025-08-10 12:40:36 +03:00
if not schemas:
2025-08-03 11:40:22 +03:00
return
substitutions = operation.getQ_substitutions()
2025-08-05 14:26:56 +03:00
receiver = OperationSchema.create_input(self.model, operation)
parents: dict = {}
children: dict = {}
for operand in schemas:
2025-08-03 11:40:22 +03:00
items = list(Constituenta.objects.filter(schema_id=operand).order_by('order'))
new_items = receiver.insert_copy(items)
for (i, cst) in enumerate(new_items):
parents[cst.pk] = items[i]
children[items[i].pk] = cst
translated_substitutions: list[tuple[Constituenta, Constituenta]] = []
for sub in substitutions:
original = children[sub.original.pk]
replacement = children[sub.substitution.pk]
translated_substitutions.append((original, replacement))
receiver.substitute(translated_substitutions)
2025-08-03 11:40:22 +03:00
for cst in Constituenta.objects.filter(schema=receiver.model).order_by('order'):
parent = parents.get(cst.pk)
assert parent is not None
Inheritance.objects.create(
operation_id=operation.pk,
child=cst,
parent=parent
)
2025-08-03 11:40:22 +03:00
OrderManager(receiver).restore_order()
receiver.reset_aliases()
2024-09-11 13:24:52 +03:00
receiver.resolve_all_text()