From 4f9f27dfd34b563ce8730d17206b0a3ae31de642 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Wed, 31 Jul 2024 21:10:34 +0300 Subject: [PATCH] R: Backend cleanup and query improvements --- TODO.txt | 6 +- .../apps/oss/models/OperationSchema.py | 2 +- .../apps/oss/serializers/data_access.py | 12 ++-- .../backend/apps/rsform/models/RSForm.py | 68 +++++++++---------- .../apps/rsform/serializers/data_access.py | 26 +++---- .../backend/apps/rsform/views/rsforms.py | 4 +- rsconcept/backend/shared/permissions.py | 2 +- 7 files changed, 59 insertions(+), 61 deletions(-) diff --git a/TODO.txt b/TODO.txt index 8c9ec45d..7fdbd15c 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,10 +2,8 @@ For more specific TODOs see comments in code [Functionality - PROGRESS] -- Operational synthesis schema as LibraryItem ? - -- Library organization, search and exploration. Consider new user experience -- Private projects and permissions. Consider cooperative editing +- Design first user experience +- Private projects. Consider cooperative editing [Functionality - PENDING] diff --git a/rsconcept/backend/apps/oss/models/OperationSchema.py b/rsconcept/backend/apps/oss/models/OperationSchema.py index 4d8498e9..e8dc9839 100644 --- a/rsconcept/backend/apps/oss/models/OperationSchema.py +++ b/rsconcept/backend/apps/oss/models/OperationSchema.py @@ -198,7 +198,7 @@ class OperationSchema: # TODO: remove duplicates from diamond for cst in receiver.constituents(): - parent = parents.get(cst.id) + parent = parents.get(cst.pk) assert parent is not None Inheritance.objects.create( child=cst, diff --git a/rsconcept/backend/apps/oss/serializers/data_access.py b/rsconcept/backend/apps/oss/serializers/data_access.py index 9c4e7de6..97148598 100644 --- a/rsconcept/backend/apps/oss/serializers/data_access.py +++ b/rsconcept/backend/apps/oss/serializers/data_access.py @@ -91,24 +91,24 @@ class OperationUpdateSerializer(serializers.Serializer): if 'substitutions' not in 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'] to_delete = {x['original'].pk for x in substitutions} deleted = set() for item in substitutions: original_cst = cast(Constituenta, item['original']) 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({ - 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({ - 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: 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: raise serializers.ValidationError({ diff --git a/rsconcept/backend/apps/rsform/models/RSForm.py b/rsconcept/backend/apps/rsform/models/RSForm.py index 8718f724..640cd10c 100644 --- a/rsconcept/backend/apps/rsform/models/RSForm.py +++ b/rsconcept/backend/apps/rsform/models/RSForm.py @@ -142,7 +142,7 @@ class RSForm: result.definition_resolved = resolver.resolve(result.definition_raw) result.save() - self.on_term_change([result.id]) + self.on_term_change([result.pk]) result.refresh_from_db() return result @@ -213,7 +213,7 @@ class RSForm: count_bot = 0 size = len(listCst) 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 count_top + 1 < target: cst.order = count_top + 1 @@ -248,7 +248,7 @@ class RSForm: mapping = {original.alias: substitution.alias} self.apply_mapping(mapping) original.delete() - self.on_term_change([substitution.id]) + self.on_term_change([substitution.pk]) def restore_order(self): ''' Restore order based on types and term graph. ''' @@ -335,7 +335,7 @@ class RSForm: definition_formal=text, cst_type=cst_type ) - result.append(new_item.id) + result.append(new_item.pk) free_index = free_index + 1 position = position + 1 @@ -347,7 +347,7 @@ class RSForm: return update_list = \ Constituenta.objects \ - .only('id', 'order', 'schema') \ + .only('order') \ .filter(schema=self.model, order__gte=start) for cst in update_list: cst.order += shift @@ -372,7 +372,7 @@ class RSForm: @transaction.atomic def _reset_order(self): 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: cst.order = order cst.save() @@ -383,15 +383,15 @@ class RSForm: result: Graph[int] = Graph() cst_list = \ self.constituents() \ - .only('id', 'order', 'alias', 'definition_formal') \ + .only('alias', 'definition_formal') \ .order_by('order') for cst in cst_list: - result.add_node(cst.id) + result.add_node(cst.pk) for cst in cst_list: for alias in extract_globals(cst.definition_formal): try: 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: pass return result @@ -401,15 +401,15 @@ class RSForm: result: Graph[int] = Graph() cst_list = \ self.constituents() \ - .only('id', 'order', 'alias', 'term_raw') \ + .only('alias', 'term_raw') \ .order_by('order') for cst in cst_list: - result.add_node(cst.id) + result.add_node(cst.pk) for cst in cst_list: for alias in extract_entities(cst.term_raw): try: 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: pass return result @@ -419,15 +419,15 @@ class RSForm: result: Graph[int] = Graph() cst_list = \ self.constituents() \ - .only('id', 'order', 'alias', 'definition_raw') \ + .only('alias', 'definition_raw') \ .order_by('order') for cst in cst_list: - result.add_node(cst.id) + result.add_node(cst.pk) for cst in cst_list: for alias in extract_entities(cst.definition_raw): try: 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: pass return result @@ -440,16 +440,16 @@ class SemanticInfo: self._graph = schema._graph_formal() self._items = list( schema.constituents() - .only('id', 'alias', 'cst_type', 'definition_formal') + .only('alias', 'cst_type', 'definition_formal') .order_by('order') ) 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 = { - cst.id: { + cst.pk: { 'is_simple': False, 'is_template': False, - 'parent': cst.id, + 'parent': cst.pk, 'children': [] } for cst in self._items @@ -491,7 +491,7 @@ class SemanticInfo: if target.cst_type == CstType.STRUCTURED or is_base_set(target.cst_type): return False - dependencies = self._graph.inputs[target.id] + dependencies = self._graph.inputs[target.pk] has_complex_dependency = any( self.is_template(cst_id) and 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: sources = self._extract_sources(target) if len(sources) != 1: - return target.id + return target.pk parent_id = next(iter(sources)) parent = self._cst_by_ID[parent_id] if is_base_set(parent.cst_type): - return target.id + return target.pk return parent_id def _extract_sources(self, target: Constituenta) -> set[int]: sources: set[int] = set() 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] if not parent_info['is_template'] or not parent_info['is_simple']: sources.add(parent_info['parent']) @@ -531,7 +531,7 @@ class SemanticInfo: if not parent: continue - parent_info = self[parent.id] + parent_info = self[parent.pk] if not parent_info['is_template'] or not parent_info['is_simple']: sources.add(parent_info['parent']) @@ -542,7 +542,7 @@ class SemanticInfo: if not parent: continue - parent_info = self[parent.id] + parent_info = self[parent.pk] if not is_base_set(parent.cst_type) and \ (not parent_info['is_template'] or not parent_info['is_simple']): sources.add(parent_info['parent']) @@ -567,10 +567,10 @@ class _OrderManager: self._graph = schema._graph_formal() self._items = list( schema.constituents() - .only('id', 'order', 'alias', 'cst_type', 'definition_formal') + .only('order', 'alias', 'cst_type', 'definition_formal') .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: ''' Implement order restoration process. ''' @@ -582,20 +582,20 @@ class _OrderManager: self._save_order() def _fix_topological(self) -> None: - sorted_ids = self._graph.sort_stable([cst.id for cst in self._items]) - sorted_items = [next(cst for cst in self._items if cst.id == id) for id in sorted_ids] + sorted_ids = self._graph.sort_stable([cst.pk for cst in self._items]) + sorted_items = [next(cst for cst in self._items if cst.pk == id) for id in sorted_ids] self._items = sorted_items def _fix_kernel(self) -> None: 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] 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 - 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) - 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] self._items = result @@ -606,11 +606,11 @@ class _OrderManager: if cst in marked: continue result.append(cst) - children = self._semantic[cst.id]['children'] + children = self._semantic[cst.pk]['children'] if len(children) == 0: continue for child in self._items: - if child.id in children: + if child.pk in children: marked.add(child) result.append(child) self._items = result diff --git a/rsconcept/backend/apps/rsform/serializers/data_access.py b/rsconcept/backend/apps/rsform/serializers/data_access.py index cace4404..e768c8e6 100644 --- a/rsconcept/backend/apps/rsform/serializers/data_access.py +++ b/rsconcept/backend/apps/rsform/serializers/data_access.py @@ -48,7 +48,7 @@ class CstSerializer(serializers.ModelSerializer): term_changed = data['term_resolved'] != instance.term_resolved result: Constituenta = super().update(instance, data) if term_changed: - schema.on_term_change([result.id]) + schema.on_term_change([result.pk]) result.refresh_from_db() schema.save() return result @@ -212,11 +212,11 @@ class CstTargetSerializer(serializers.Serializer): cst = cast(Constituenta, attrs['target']) if schema and cst.schema != schema: 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]: raise serializers.ValidationError({ - f'{cst.id}': msg.constituentaNoStructure() + f'{cst.pk}': msg.constituentaNoStructure() }) self.instance = cst return attrs @@ -234,7 +234,7 @@ class CstRenameSerializer(serializers.Serializer): cst = cast(Constituenta, attrs['target']) if cst.schema != schema: raise serializers.ValidationError({ - f'{cst.id}': msg.constituentaNotInRSform(schema.title) + f'{cst.pk}': msg.constituentaNotInRSform(schema.title) }) new_alias = self.initial_data['alias'] if cst.alias == new_alias: @@ -260,7 +260,7 @@ class CstListSerializer(serializers.Serializer): for item in attrs['items']: if item.schema != schema: raise serializers.ValidationError({ - f'{item.id}': msg.constituentaNotInRSform(schema.title) + f'{item.pk}': msg.constituentaNotInRSform(schema.title) }) return attrs @@ -291,7 +291,7 @@ class CstSubstituteSerializer(serializers.Serializer): substitution_cst = cast(Constituenta, item['substitution']) if original_cst.pk in deleted: 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: 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): raise PermissionDenied({ 'message': msg.schemaForbidden(), - 'object_id': schema_in.id + 'object_id': schema_in.pk }) constituents = cast(list[Constituenta], attrs['items']) for cst in constituents: if cst.schema != schema_in: raise serializers.ValidationError({ - f'{cst.id}': msg.constituentaNotInRSform(schema_in.title) + f'{cst.pk}': msg.constituentaNotInRSform(schema_in.title) }) deleted = set() for item in attrs['substitutions']: @@ -340,24 +340,24 @@ class InlineSynthesisSerializer(serializers.Serializer): if original_cst.schema == schema_in: if original_cst not in constituents: raise serializers.ValidationError({ - f'{original_cst.id}': msg.substitutionNotInList() + f'{original_cst.pk}': msg.substitutionNotInList() }) if substitution_cst.schema != schema_out: raise serializers.ValidationError({ - f'{substitution_cst.id}': msg.constituentaNotInRSform(schema_out.title) + f'{substitution_cst.pk}': msg.constituentaNotInRSform(schema_out.title) }) else: if substitution_cst not in constituents: raise serializers.ValidationError({ - f'{substitution_cst.id}': msg.substitutionNotInList() + f'{substitution_cst.pk}': msg.substitutionNotInList() }) if original_cst.schema != schema_out: 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: 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) return attrs diff --git a/rsconcept/backend/apps/rsform/views/rsforms.py b/rsconcept/backend/apps/rsform/views/rsforms.py index cc88af5d..7b99d8b1 100644 --- a/rsconcept/backend/apps/rsform/views/rsforms.py +++ b/rsconcept/backend/apps/rsform/views/rsforms.py @@ -149,11 +149,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr cst = cast(m.Constituenta, serializer.validated_data['target']) 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']: return Response( 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) diff --git a/rsconcept/backend/shared/permissions.py b/rsconcept/backend/shared/permissions.py index 71c73395..d8de8873 100644 --- a/rsconcept/backend/shared/permissions.py +++ b/rsconcept/backend/shared/permissions.py @@ -28,7 +28,7 @@ def _extract_item(obj: Any) -> LibraryItem: return cast(LibraryItem, obj.item) raise PermissionDenied({ 'message': 'Invalid type error. Please contact developers', - 'object_id': obj.id + 'object_id': obj.pk })