R: Backend cleanup and query improvements
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
Frontend CI / build (22.x) (push) Waiting to run

This commit is contained in:
Ivan 2024-07-31 21:10:34 +03:00
parent 16a225a959
commit 4f9f27dfd3
7 changed files with 59 additions and 61 deletions

View File

@ -2,10 +2,8 @@
For more specific TODOs see comments in code For more specific TODOs see comments in code
[Functionality - PROGRESS] [Functionality - PROGRESS]
- Operational synthesis schema as LibraryItem ? - Design first user experience
- Private projects. Consider cooperative editing
- Library organization, search and exploration. Consider new user experience
- Private projects and permissions. Consider cooperative editing
[Functionality - PENDING] [Functionality - PENDING]

View File

@ -198,7 +198,7 @@ class OperationSchema:
# TODO: remove duplicates from diamond # TODO: remove duplicates from diamond
for cst in receiver.constituents(): for cst in receiver.constituents():
parent = parents.get(cst.id) parent = parents.get(cst.pk)
assert parent is not None assert parent is not None
Inheritance.objects.create( Inheritance.objects.create(
child=cst, child=cst,

View File

@ -91,24 +91,24 @@ class OperationUpdateSerializer(serializers.Serializer):
if 'substitutions' not in attrs: if 'substitutions' not in attrs:
return attrs return attrs
schemas = [arg.result.pk for arg in attrs['arguments'] if arg.result is not None] schemas = [arg.result_id for arg in attrs['arguments'] if arg.result is not None]
substitutions = attrs['substitutions'] substitutions = attrs['substitutions']
to_delete = {x['original'].pk for x in substitutions} to_delete = {x['original'].pk for x in substitutions}
deleted = set() deleted = set()
for item in substitutions: for item in substitutions:
original_cst = cast(Constituenta, item['original']) original_cst = cast(Constituenta, item['original'])
substitution_cst = cast(Constituenta, item['substitution']) substitution_cst = cast(Constituenta, item['substitution'])
if original_cst.schema.pk not in schemas: if original_cst.schema_id not in schemas:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.constituentaNotFromOperation() f'{original_cst.pk}': msg.constituentaNotFromOperation()
}) })
if substitution_cst.schema.pk not in schemas: if substitution_cst.schema_id not in schemas:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{substitution_cst.id}': msg.constituentaNotFromOperation() f'{substitution_cst.pk}': msg.constituentaNotFromOperation()
}) })
if original_cst.pk in deleted or substitution_cst.pk in to_delete: if original_cst.pk in deleted or substitution_cst.pk in to_delete:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.substituteDouble(original_cst.alias) f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
}) })
if original_cst.schema == substitution_cst.schema: if original_cst.schema == substitution_cst.schema:
raise serializers.ValidationError({ raise serializers.ValidationError({

View File

@ -142,7 +142,7 @@ class RSForm:
result.definition_resolved = resolver.resolve(result.definition_raw) result.definition_resolved = resolver.resolve(result.definition_raw)
result.save() result.save()
self.on_term_change([result.id]) self.on_term_change([result.pk])
result.refresh_from_db() result.refresh_from_db()
return result return result
@ -213,7 +213,7 @@ class RSForm:
count_bot = 0 count_bot = 0
size = len(listCst) size = len(listCst)
update_list = [] update_list = []
for cst in self.constituents().only('id', 'order').order_by('order'): for cst in self.constituents().only('order').order_by('order'):
if cst not in listCst: if cst not in listCst:
if count_top + 1 < target: if count_top + 1 < target:
cst.order = count_top + 1 cst.order = count_top + 1
@ -248,7 +248,7 @@ class RSForm:
mapping = {original.alias: substitution.alias} mapping = {original.alias: substitution.alias}
self.apply_mapping(mapping) self.apply_mapping(mapping)
original.delete() original.delete()
self.on_term_change([substitution.id]) self.on_term_change([substitution.pk])
def restore_order(self): def restore_order(self):
''' Restore order based on types and term graph. ''' ''' Restore order based on types and term graph. '''
@ -335,7 +335,7 @@ class RSForm:
definition_formal=text, definition_formal=text,
cst_type=cst_type cst_type=cst_type
) )
result.append(new_item.id) result.append(new_item.pk)
free_index = free_index + 1 free_index = free_index + 1
position = position + 1 position = position + 1
@ -347,7 +347,7 @@ class RSForm:
return return
update_list = \ update_list = \
Constituenta.objects \ Constituenta.objects \
.only('id', 'order', 'schema') \ .only('order') \
.filter(schema=self.model, order__gte=start) .filter(schema=self.model, order__gte=start)
for cst in update_list: for cst in update_list:
cst.order += shift cst.order += shift
@ -372,7 +372,7 @@ class RSForm:
@transaction.atomic @transaction.atomic
def _reset_order(self): def _reset_order(self):
order = 1 order = 1
for cst in self.constituents().only('id', 'order').order_by('order'): for cst in self.constituents().only('order').order_by('order'):
if cst.order != order: if cst.order != order:
cst.order = order cst.order = order
cst.save() cst.save()
@ -383,15 +383,15 @@ class RSForm:
result: Graph[int] = Graph() result: Graph[int] = Graph()
cst_list = \ cst_list = \
self.constituents() \ self.constituents() \
.only('id', 'order', 'alias', 'definition_formal') \ .only('alias', 'definition_formal') \
.order_by('order') .order_by('order')
for cst in cst_list: for cst in cst_list:
result.add_node(cst.id) result.add_node(cst.pk)
for cst in cst_list: for cst in cst_list:
for alias in extract_globals(cst.definition_formal): for alias in extract_globals(cst.definition_formal):
try: try:
child = cst_list.get(alias=alias) child = cst_list.get(alias=alias)
result.add_edge(src=child.id, dest=cst.id) result.add_edge(src=child.pk, dest=cst.pk)
except Constituenta.DoesNotExist: except Constituenta.DoesNotExist:
pass pass
return result return result
@ -401,15 +401,15 @@ class RSForm:
result: Graph[int] = Graph() result: Graph[int] = Graph()
cst_list = \ cst_list = \
self.constituents() \ self.constituents() \
.only('id', 'order', 'alias', 'term_raw') \ .only('alias', 'term_raw') \
.order_by('order') .order_by('order')
for cst in cst_list: for cst in cst_list:
result.add_node(cst.id) result.add_node(cst.pk)
for cst in cst_list: for cst in cst_list:
for alias in extract_entities(cst.term_raw): for alias in extract_entities(cst.term_raw):
try: try:
child = cst_list.get(alias=alias) child = cst_list.get(alias=alias)
result.add_edge(src=child.id, dest=cst.id) result.add_edge(src=child.pk, dest=cst.pk)
except Constituenta.DoesNotExist: except Constituenta.DoesNotExist:
pass pass
return result return result
@ -419,15 +419,15 @@ class RSForm:
result: Graph[int] = Graph() result: Graph[int] = Graph()
cst_list = \ cst_list = \
self.constituents() \ self.constituents() \
.only('id', 'order', 'alias', 'definition_raw') \ .only('alias', 'definition_raw') \
.order_by('order') .order_by('order')
for cst in cst_list: for cst in cst_list:
result.add_node(cst.id) result.add_node(cst.pk)
for cst in cst_list: for cst in cst_list:
for alias in extract_entities(cst.definition_raw): for alias in extract_entities(cst.definition_raw):
try: try:
child = cst_list.get(alias=alias) child = cst_list.get(alias=alias)
result.add_edge(src=child.id, dest=cst.id) result.add_edge(src=child.pk, dest=cst.pk)
except Constituenta.DoesNotExist: except Constituenta.DoesNotExist:
pass pass
return result return result
@ -440,16 +440,16 @@ class SemanticInfo:
self._graph = schema._graph_formal() self._graph = schema._graph_formal()
self._items = list( self._items = list(
schema.constituents() schema.constituents()
.only('id', 'alias', 'cst_type', 'definition_formal') .only('alias', 'cst_type', 'definition_formal')
.order_by('order') .order_by('order')
) )
self._cst_by_alias = {cst.alias: cst for cst in self._items} self._cst_by_alias = {cst.alias: cst for cst in self._items}
self._cst_by_ID = {cst.id: cst for cst in self._items} self._cst_by_ID = {cst.pk: cst for cst in self._items}
self.info = { self.info = {
cst.id: { cst.pk: {
'is_simple': False, 'is_simple': False,
'is_template': False, 'is_template': False,
'parent': cst.id, 'parent': cst.pk,
'children': [] 'children': []
} }
for cst in self._items for cst in self._items
@ -491,7 +491,7 @@ class SemanticInfo:
if target.cst_type == CstType.STRUCTURED or is_base_set(target.cst_type): if target.cst_type == CstType.STRUCTURED or is_base_set(target.cst_type):
return False return False
dependencies = self._graph.inputs[target.id] dependencies = self._graph.inputs[target.pk]
has_complex_dependency = any( has_complex_dependency = any(
self.is_template(cst_id) and self.is_template(cst_id) and
not self.is_simple_expression(cst_id) for cst_id in dependencies not self.is_simple_expression(cst_id) for cst_id in dependencies
@ -507,18 +507,18 @@ class SemanticInfo:
def _infer_parent(self, target: Constituenta) -> int: def _infer_parent(self, target: Constituenta) -> int:
sources = self._extract_sources(target) sources = self._extract_sources(target)
if len(sources) != 1: if len(sources) != 1:
return target.id return target.pk
parent_id = next(iter(sources)) parent_id = next(iter(sources))
parent = self._cst_by_ID[parent_id] parent = self._cst_by_ID[parent_id]
if is_base_set(parent.cst_type): if is_base_set(parent.cst_type):
return target.id return target.pk
return parent_id return parent_id
def _extract_sources(self, target: Constituenta) -> set[int]: def _extract_sources(self, target: Constituenta) -> set[int]:
sources: set[int] = set() sources: set[int] = set()
if not is_functional(target.cst_type): if not is_functional(target.cst_type):
for parent_id in self._graph.inputs[target.id]: for parent_id in self._graph.inputs[target.pk]:
parent_info = self[parent_id] parent_info = self[parent_id]
if not parent_info['is_template'] or not parent_info['is_simple']: if not parent_info['is_template'] or not parent_info['is_simple']:
sources.add(parent_info['parent']) sources.add(parent_info['parent'])
@ -531,7 +531,7 @@ class SemanticInfo:
if not parent: if not parent:
continue continue
parent_info = self[parent.id] parent_info = self[parent.pk]
if not parent_info['is_template'] or not parent_info['is_simple']: if not parent_info['is_template'] or not parent_info['is_simple']:
sources.add(parent_info['parent']) sources.add(parent_info['parent'])
@ -542,7 +542,7 @@ class SemanticInfo:
if not parent: if not parent:
continue continue
parent_info = self[parent.id] parent_info = self[parent.pk]
if not is_base_set(parent.cst_type) and \ if not is_base_set(parent.cst_type) and \
(not parent_info['is_template'] or not parent_info['is_simple']): (not parent_info['is_template'] or not parent_info['is_simple']):
sources.add(parent_info['parent']) sources.add(parent_info['parent'])
@ -567,10 +567,10 @@ class _OrderManager:
self._graph = schema._graph_formal() self._graph = schema._graph_formal()
self._items = list( self._items = list(
schema.constituents() schema.constituents()
.only('id', 'order', 'alias', 'cst_type', 'definition_formal') .only('order', 'alias', 'cst_type', 'definition_formal')
.order_by('order') .order_by('order')
) )
self._cst_by_ID = {cst.id: cst for cst in self._items} self._cst_by_ID = {cst.pk: cst for cst in self._items}
def restore_order(self) -> None: def restore_order(self) -> None:
''' Implement order restoration process. ''' ''' Implement order restoration process. '''
@ -582,20 +582,20 @@ class _OrderManager:
self._save_order() self._save_order()
def _fix_topological(self) -> None: def _fix_topological(self) -> None:
sorted_ids = self._graph.sort_stable([cst.id for cst in self._items]) sorted_ids = self._graph.sort_stable([cst.pk for cst in self._items])
sorted_items = [next(cst for cst in self._items if cst.id == id) for id in sorted_ids] sorted_items = [next(cst for cst in self._items if cst.pk == id) for id in sorted_ids]
self._items = sorted_items self._items = sorted_items
def _fix_kernel(self) -> None: def _fix_kernel(self) -> None:
result = [cst for cst in self._items if cst.cst_type == CstType.BASE] result = [cst for cst in self._items if cst.cst_type == CstType.BASE]
result = result + [cst for cst in self._items if cst.cst_type == CstType.CONSTANT] result = result + [cst for cst in self._items if cst.cst_type == CstType.CONSTANT]
kernel = [ kernel = [
cst.id for cst in self._items if cst.pk for cst in self._items if
cst.cst_type in [CstType.STRUCTURED, CstType.AXIOM] or cst.cst_type in [CstType.STRUCTURED, CstType.AXIOM] or
self._cst_by_ID[self._semantic.parent(cst.id)].cst_type == CstType.STRUCTURED self._cst_by_ID[self._semantic.parent(cst.pk)].cst_type == CstType.STRUCTURED
] ]
kernel = kernel + self._graph.expand_inputs(kernel) kernel = kernel + self._graph.expand_inputs(kernel)
result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.id in kernel] result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.pk in kernel]
result = result + [cst for cst in self._items if result.count(cst) == 0] result = result + [cst for cst in self._items if result.count(cst) == 0]
self._items = result self._items = result
@ -606,11 +606,11 @@ class _OrderManager:
if cst in marked: if cst in marked:
continue continue
result.append(cst) result.append(cst)
children = self._semantic[cst.id]['children'] children = self._semantic[cst.pk]['children']
if len(children) == 0: if len(children) == 0:
continue continue
for child in self._items: for child in self._items:
if child.id in children: if child.pk in children:
marked.add(child) marked.add(child)
result.append(child) result.append(child)
self._items = result self._items = result

View File

@ -48,7 +48,7 @@ class CstSerializer(serializers.ModelSerializer):
term_changed = data['term_resolved'] != instance.term_resolved term_changed = data['term_resolved'] != instance.term_resolved
result: Constituenta = super().update(instance, data) result: Constituenta = super().update(instance, data)
if term_changed: if term_changed:
schema.on_term_change([result.id]) schema.on_term_change([result.pk])
result.refresh_from_db() result.refresh_from_db()
schema.save() schema.save()
return result return result
@ -212,11 +212,11 @@ class CstTargetSerializer(serializers.Serializer):
cst = cast(Constituenta, attrs['target']) cst = cast(Constituenta, attrs['target'])
if schema and cst.schema != schema: if schema and cst.schema != schema:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{cst.id}': msg.constituentaNotInRSform(schema.title) f'{cst.pk}': msg.constituentaNotInRSform(schema.title)
}) })
if cst.cst_type not in [CstType.FUNCTION, CstType.STRUCTURED, CstType.TERM]: if cst.cst_type not in [CstType.FUNCTION, CstType.STRUCTURED, CstType.TERM]:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{cst.id}': msg.constituentaNoStructure() f'{cst.pk}': msg.constituentaNoStructure()
}) })
self.instance = cst self.instance = cst
return attrs return attrs
@ -234,7 +234,7 @@ class CstRenameSerializer(serializers.Serializer):
cst = cast(Constituenta, attrs['target']) cst = cast(Constituenta, attrs['target'])
if cst.schema != schema: if cst.schema != schema:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{cst.id}': msg.constituentaNotInRSform(schema.title) f'{cst.pk}': msg.constituentaNotInRSform(schema.title)
}) })
new_alias = self.initial_data['alias'] new_alias = self.initial_data['alias']
if cst.alias == new_alias: if cst.alias == new_alias:
@ -260,7 +260,7 @@ class CstListSerializer(serializers.Serializer):
for item in attrs['items']: for item in attrs['items']:
if item.schema != schema: if item.schema != schema:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{item.id}': msg.constituentaNotInRSform(schema.title) f'{item.pk}': msg.constituentaNotInRSform(schema.title)
}) })
return attrs return attrs
@ -291,7 +291,7 @@ class CstSubstituteSerializer(serializers.Serializer):
substitution_cst = cast(Constituenta, item['substitution']) substitution_cst = cast(Constituenta, item['substitution'])
if original_cst.pk in deleted: if original_cst.pk in deleted:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.substituteDouble(original_cst.alias) f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
}) })
if original_cst.alias == substitution_cst.alias: if original_cst.alias == substitution_cst.alias:
raise serializers.ValidationError({ raise serializers.ValidationError({
@ -325,13 +325,13 @@ class InlineSynthesisSerializer(serializers.Serializer):
if user.is_anonymous or (schema_out.owner != user and not user.is_staff): if user.is_anonymous or (schema_out.owner != user and not user.is_staff):
raise PermissionDenied({ raise PermissionDenied({
'message': msg.schemaForbidden(), 'message': msg.schemaForbidden(),
'object_id': schema_in.id 'object_id': schema_in.pk
}) })
constituents = cast(list[Constituenta], attrs['items']) constituents = cast(list[Constituenta], attrs['items'])
for cst in constituents: for cst in constituents:
if cst.schema != schema_in: if cst.schema != schema_in:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{cst.id}': msg.constituentaNotInRSform(schema_in.title) f'{cst.pk}': msg.constituentaNotInRSform(schema_in.title)
}) })
deleted = set() deleted = set()
for item in attrs['substitutions']: for item in attrs['substitutions']:
@ -340,24 +340,24 @@ class InlineSynthesisSerializer(serializers.Serializer):
if original_cst.schema == schema_in: if original_cst.schema == schema_in:
if original_cst not in constituents: if original_cst not in constituents:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.substitutionNotInList() f'{original_cst.pk}': msg.substitutionNotInList()
}) })
if substitution_cst.schema != schema_out: if substitution_cst.schema != schema_out:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{substitution_cst.id}': msg.constituentaNotInRSform(schema_out.title) f'{substitution_cst.pk}': msg.constituentaNotInRSform(schema_out.title)
}) })
else: else:
if substitution_cst not in constituents: if substitution_cst not in constituents:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{substitution_cst.id}': msg.substitutionNotInList() f'{substitution_cst.pk}': msg.substitutionNotInList()
}) })
if original_cst.schema != schema_out: if original_cst.schema != schema_out:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.constituentaNotInRSform(schema_out.title) f'{original_cst.pk}': msg.constituentaNotInRSform(schema_out.title)
}) })
if original_cst.pk in deleted: if original_cst.pk in deleted:
raise serializers.ValidationError({ raise serializers.ValidationError({
f'{original_cst.id}': msg.substituteDouble(original_cst.alias) f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
}) })
deleted.add(original_cst.pk) deleted.add(original_cst.pk)
return attrs return attrs

View File

@ -149,11 +149,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
cst = cast(m.Constituenta, serializer.validated_data['target']) cst = cast(m.Constituenta, serializer.validated_data['target'])
schema_details = s.RSFormParseSerializer(schema).data['items'] schema_details = s.RSFormParseSerializer(schema).data['items']
cst_parse = next(item for item in schema_details if item['id'] == cst.id)['parse'] cst_parse = next(item for item in schema_details if item['id'] == cst.pk)['parse']
if not cst_parse['typification']: if not cst_parse['typification']:
return Response( return Response(
status=c.HTTP_400_BAD_REQUEST, status=c.HTTP_400_BAD_REQUEST,
data={f'{cst.id}': msg.constituentaNoStructure()} data={f'{cst.pk}': msg.constituentaNoStructure()}
) )
result = m.RSForm(schema).produce_structure(cst, cst_parse) result = m.RSForm(schema).produce_structure(cst, cst_parse)

View File

@ -28,7 +28,7 @@ def _extract_item(obj: Any) -> LibraryItem:
return cast(LibraryItem, obj.item) return cast(LibraryItem, obj.item)
raise PermissionDenied({ raise PermissionDenied({
'message': 'Invalid type error. Please contact developers', 'message': 'Invalid type error. Please contact developers',
'object_id': obj.id 'object_id': obj.pk
}) })