ConceptPortal-public/rsconcept/backend/apps/rsform/models/RSForm.py

142 lines
5.1 KiB
Python
Raw Normal View History

''' Models: RSForm API. '''
2025-08-01 10:55:53 +03:00
# pylint: disable=duplicate-code
2025-08-01 10:55:53 +03:00
from typing import Iterable, Optional
from cctext import Entity, Resolver, TermForm, split_grams
2024-05-24 18:31:14 +03:00
from django.core.exceptions import ValidationError
from django.db.models import QuerySet
from apps.library.models import LibraryItem, LibraryItemType, Version
2024-07-19 19:29:27 +03:00
from shared import messages as msg
2025-08-01 10:55:53 +03:00
from .api_RSLanguage import guess_type
from .Constituenta import Constituenta, CstType
INSERT_LAST: int = -1
2024-08-11 12:38:08 +03:00
DELETED_ALIAS = 'DEL'
class RSForm:
2025-08-01 10:55:53 +03:00
''' RSForm wrapper. No caching, each mutation requires querying. '''
def __init__(self, model: LibraryItem):
2025-08-01 10:55:53 +03:00
assert model.item_type == LibraryItemType.RSFORM
self.model = model
2023-08-25 22:51:20 +03:00
@staticmethod
def create(**kwargs) -> 'RSForm':
''' Create LibraryItem via RSForm. '''
model = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, **kwargs)
return RSForm(model)
2024-07-22 21:20:51 +03:00
@staticmethod
2025-08-01 10:55:53 +03:00
def spawn_resolver(schemaID: int) -> Resolver:
''' Create resolver for text references based on schema terms. '''
result = Resolver({})
2025-08-01 10:55:53 +03:00
constituents = Constituenta.objects.filter(schema_id=schemaID).only('alias', 'term_resolved', 'term_forms')
for cst in constituents:
2023-09-25 14:17:52 +03:00
entity = Entity(
alias=cst.alias,
nominal=cst.term_resolved,
manual_forms=[
TermForm(text=form['text'], grams=split_grams(form['tags']))
for form in cst.term_forms
]
)
result.context[cst.alias] = entity
return result
2025-08-01 10:55:53 +03:00
def refresh_from_db(self) -> None:
''' Model wrapper. '''
self.model.refresh_from_db()
2024-07-15 12:36:18 +03:00
2025-08-01 10:55:53 +03:00
def save(self, *args, **kwargs) -> None:
''' Model wrapper. '''
self.model.save(*args, **kwargs)
2024-07-15 12:36:18 +03:00
2025-08-01 10:55:53 +03:00
def constituentsQ(self) -> QuerySet[Constituenta]:
''' Get QuerySet containing all constituents of current RSForm. '''
return Constituenta.objects.filter(schema=self.model)
2024-07-15 12:36:18 +03:00
2025-08-01 10:55:53 +03:00
def insert_last(
self,
alias: str,
2024-07-15 12:36:18 +03:00
cst_type: Optional[CstType] = None,
**kwargs
) -> Constituenta:
2025-08-01 10:55:53 +03:00
''' Insert new constituenta at last position. '''
if Constituenta.objects.filter(schema=self.model, alias=alias).exists():
raise ValidationError(msg.aliasTaken(alias))
if cst_type is None:
cst_type = guess_type(alias)
2025-08-01 10:55:53 +03:00
position = self.constituentsQ().count()
result = Constituenta.objects.create(
schema=self.model,
2023-07-15 17:46:19 +03:00
order=position,
alias=alias,
cst_type=cst_type,
**kwargs
2023-07-15 17:46:19 +03:00
)
2025-08-01 10:55:53 +03:00
self.model.save(update_fields=['time_update'])
return result
2023-07-15 17:46:19 +03:00
2024-08-07 21:54:50 +03:00
def move_cst(self, target: list[Constituenta], destination: int) -> None:
2025-08-01 10:55:53 +03:00
''' Move list of constituents to specific position. '''
count_moved = 0
count_top = 0
count_bot = 0
2024-08-07 21:54:50 +03:00
size = len(target)
2025-08-01 10:55:53 +03:00
cst_list = Constituenta.objects.filter(schema=self.model).only('order').order_by('order')
2024-08-07 21:54:50 +03:00
for cst in cst_list:
if cst in target:
cst.order = destination + count_moved
count_moved += 1
elif count_top < destination:
cst.order = count_top
2024-08-07 21:54:50 +03:00
count_top += 1
else:
cst.order = destination + size + count_bot
count_bot += 1
Constituenta.objects.bulk_update(cst_list, ['order'])
2024-08-12 16:52:06 +03:00
self.save(update_fields=['time_update'])
2024-08-07 21:54:50 +03:00
def delete_cst(self, target: Iterable[Constituenta]) -> None:
''' Delete multiple constituents. Do not check if listCst are from this schema. '''
2024-08-11 12:38:08 +03:00
mapping = {cst.alias: DELETED_ALIAS for cst in target}
self.apply_mapping(mapping)
2024-08-07 21:54:50 +03:00
Constituenta.objects.filter(pk__in=[cst.pk for cst in target]).delete()
self._reset_order()
2024-08-12 16:52:06 +03:00
self.save(update_fields=['time_update'])
2024-08-07 21:54:50 +03:00
def apply_mapping(self, mapping: dict[str, str], change_aliases: bool = False) -> None:
2023-08-23 12:15:16 +03:00
''' Apply rename mapping. '''
2024-08-07 21:54:50 +03:00
update_list: list[Constituenta] = []
2025-08-01 10:55:53 +03:00
constituents = self.constituentsQ().only('alias', 'definition_formal', 'term_raw', 'definition_raw')
for cst in constituents:
2024-03-12 20:11:11 +03:00
if cst.apply_mapping(mapping, change_aliases):
2024-08-07 21:54:50 +03:00
update_list.append(cst)
Constituenta.objects.bulk_update(update_list, ['alias', 'definition_formal', 'term_raw', 'definition_raw'])
2024-08-12 16:52:06 +03:00
self.save(update_fields=['time_update'])
2023-07-15 17:46:19 +03:00
def create_version(self, version: str, description: str, data) -> Version:
''' Creates version for current state. '''
return Version.objects.create(
item=self.model,
version=version,
description=description,
data=data
)
2024-08-07 21:54:50 +03:00
def _reset_order(self) -> None:
order = 0
2024-08-07 21:54:50 +03:00
changed: list[Constituenta] = []
2025-08-01 10:55:53 +03:00
cst_list = self.constituentsQ().only('order').order_by('order')
2024-08-07 21:54:50 +03:00
for cst in cst_list:
if cst.order != order:
cst.order = order
2024-08-07 21:54:50 +03:00
changed.append(cst)
order += 1
2024-08-07 21:54:50 +03:00
Constituenta.objects.bulk_update(changed, ['order'])