From 3ed11041b9b989af403c9a96b20651d511430d30 Mon Sep 17 00:00:00 2001
From: florian <f.spreckelsen@inidscale.com>
Date: Wed, 14 Jun 2023 11:03:06 +0200
Subject: [PATCH] ENH: Implement value removal function

---
 src/caosdb/common/models.py | 64 ++++++++++++++++++++++++++++++++++---
 1 file changed, 60 insertions(+), 4 deletions(-)

diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index 9ba54c49..30009f8f 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -1,12 +1,11 @@
 # -*- coding: utf-8 -*-
 #
-# ** header v3.0
 # This file is a part of the CaosDB Project.
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-# Copyright (C) 2020-2022 Indiscale GmbH <info@indiscale.com>
-# Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+# Copyright (C) 2020-2023 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2020-2023 Florian Spreckelsen <f.spreckelsen@indiscale.com>
 # Copyright (C) 2020-2022 Timm Fitschen <t.fitschen@indiscale.com>
 #
 # This program is free software: you can redistribute it and/or modify
@@ -22,7 +21,6 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program. If not, see <https://www.gnu.org/licenses/>.
 #
-# ** end header
 #
 
 """
@@ -47,6 +45,7 @@ from os import listdir
 from os.path import isdir
 from random import randint
 from tempfile import NamedTemporaryFile
+from typing import Any, Optional
 from warnings import warn
 
 from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT,
@@ -453,6 +452,63 @@ class Entity:
 
         return self
 
+    def remove_value_from_property(self, property_name: str, value: Any,
+                                   remove_if_empty_afterwards: Optional[bool] = True):
+        """Remove a value from a property given by name.
+
+        Do nothing if this entity does not have a property of this
+        ``property_name`` or if the property value is different of the given
+        ``value``. By default, the property is removed form this entity if it is
+        empty (i.e., value=None) after removal of the value. This behavior can
+        be changed by setting ``remove_if_empty_afterwards`` to ``False`` in which
+        case the property remains.
+
+        Notes
+        -----
+        If the property value is a list and the value to be removed occurs more
+        than once in this list, only it's first occurrance is deleted (similar
+        to the behavior of Python's ``list.remove()``.)
+
+        If the property is already empty and a value != None is to be removed,
+        the property is not removed afterwards even if
+        ``remove_if_empty_afterwards`` is set to ``True`` (since it hasn't been
+        emptied **because** this function was called but rather didn't have a
+        value in the first place). This changes if the value to be removed is
+        set to ``None`` explicitly.
+
+        Parameters
+        ----------
+        property_name : str
+            Name of the property from which the ``value`` will be removed.
+        value
+            Value that is to be removed.
+        remove_if_empty_afterwards : bool, optional
+            Whether the property is to be removed from this entity if it is
+            emptied by removing the ``value``. Default is ``True``.
+
+        Returns
+        -------
+        self
+            This entity.
+        """
+
+        if self.get_property(property_name) is None:
+            return self
+        empty_afterwards = False
+        if isinstance(self.get_property(property_name).value, list):
+            if value in self.get_property(property_name).value:
+                self.get_property(property_name).value.remove(value)
+                if self.get_property(property_name).value == []:
+                    self.get_property(property_name).value = None
+                    empty_afterwards = True
+        elif self.get_property(property_name).value == value:
+            self.get_property(property_name).value = None
+            empty_afterwards = True
+        if remove_if_empty_afterwards and empty_afterwards:
+            self.remove_property(property_name)
+
+        return self
+
     def remove_parent(self, parent):
         self.parents.remove(parent)
 
-- 
GitLab