From aa06422c8c92c8cbec57840082531d1447135bff Mon Sep 17 00:00:00 2001 From: Johnathan Clementi Date: Thu, 5 Sep 2024 11:35:20 -0400 Subject: [PATCH] Add concept to reference dt node migration #24 --- .../management/commands/controlled_lists.py | 106 +++++++++++++++++- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/arches_references/management/commands/controlled_lists.py b/arches_references/management/commands/controlled_lists.py index e04530f..9345839 100644 --- a/arches_references/management/commands/controlled_lists.py +++ b/arches_references/management/commands/controlled_lists.py @@ -1,5 +1,10 @@ -from arches.app.models.models import Value +from arches.app.models.models import CardXNodeXWidget, Node, GraphModel, Value +from arches_references.models import List from django.core.management.base import BaseCommand +from django.db import models +from django.db.models.expressions import CombinedExpression +from django.db.models.fields.json import KT +from django.db.models.functions import Cast class Command(BaseCommand): @@ -15,7 +20,10 @@ def add_arguments(self, parser): action="store", dest="operation", required=True, - choices=["migrate_collections_to_controlled_lists"], + choices=[ + "migrate_collections_to_controlled_lists", + "migrate_graph_to_reference_datatype", + ], help="The operation to perform", ) @@ -25,7 +33,6 @@ def add_arguments(self, parser): action="store", dest="collections_to_migrate", nargs="*", - required=True, help="One or more collections to migrate to controlled lists", ) @@ -56,6 +63,14 @@ def add_arguments(self, parser): help="The language to use for sorting preferred labels. Default 'en'", ) + parser.add_argument( + "-g", + "--graph", + action="store", + dest="graph", + help="The graphid which associated concept nodes will be migrated to use the reference datatype", + ) + def handle(self, *args, **options): if options["operation"] == "migrate_collections_to_controlled_lists": self.migrate_collections_to_controlled_lists( @@ -64,6 +79,8 @@ def handle(self, *args, **options): overwrite=options["overwrite"], preferred_sort_language=options["preferred_sort_language"], ) + elif options["operation"] == "migrate_graph_to_reference_datatype": + self.migrate_graph_to_reference_datatype(options["graph"]) def migrate_collections_to_controlled_lists( self, @@ -118,3 +135,86 @@ def migrate_collections_to_controlled_lists( ) result = cursor.fetchone() self.stdout.write(result[0]) + + def migrate_graph_to_reference_datatype(self, graph): + future_graph = GraphModel.objects.get(source_identifier=graph) + nodes = ( + Node.objects.filter( + graph_id=future_graph.graphid, + datatype__in=["concept", "concept-list"], + is_immutable=False, + ) + .annotate( + collection_id=Cast( + KT("config__rdmCollection"), + output_field=models.UUIDField(), + ) + ) + .prefetch_related("cardxnodexwidget_set") + ) + + existing_list_ids = List.objects.all().values_list("id", flat=True) + + errors = [] + for node in nodes: + if node.collection_id in existing_list_ids: + if node.datatype == "concept": + node.config = { + "multiValue": False, + "controlledList": node.collection_id.__str__(), + } + elif node.datatype == "concept-list": + node.config = { + "multiValue": True, + "controlledList": node.collection_id.__str__(), + } + node.datatype = "reference" + node.save() + + cross_records = ( + node.cardxnodexwidget_set.annotate( + config_without_i18n=Cast( + models.F("config"), + output_field=models.JSONField(), + ) + ) + .annotate( + without_default=CombinedExpression( + models.F("config_without_i18n"), + "-", + models.Value( + "defaultValue", output_field=models.CharField() + ), + output_field=models.JSONField(), + ) + ) + .annotate( + without_default_and_options=CombinedExpression( + models.F("without_default"), + "-", + models.Value("options", output_field=models.CharField()), + output_field=models.JSONField(), + ) + ) + ) + for cross_record in cross_records: + cross_record.config = cross_record.without_default_and_options + cross_record.save() + elif node.collection_id not in existing_list_ids: + errors.append( + {"node_alias": node.alias, "collection_id": node.collection_id} + ) + + if errors: + self.stderr.write( + "The following collections for the associated nodes have not been migrated to controlled lists: {0}".format( + errors + ) + ) + else: + future_graph.has_unpublished_changes = True + self.stdout.write( + "All concept nodes for the {0} graph have been successfully migrated to reference datatype".format( + future_graph.name + ) + )