From 7962c03008cac5a6634d0483f5333bf9cd7990d0 Mon Sep 17 00:00:00 2001
From: Alexander Schlemmer <alexander@mail-schlemmer.de>
Date: Tue, 1 Feb 2022 13:10:51 +0100
Subject: [PATCH] ENH: Added a function for copying an entity including tests

---
 src/caosdb/apiutils.py     | 41 +++++++++++++++++++++++++++++++++++++-
 unittests/test_apiutils.py | 22 +++++++++++++++++++-
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py
index a8256976..e126b843 100644
--- a/src/caosdb/apiutils.py
+++ b/src/caosdb/apiutils.py
@@ -557,7 +557,7 @@ def getCommitIn(folder):
         return t.readline().strip()
 
 
-COMPARED = ["name", "role", "datatype", "description", "importance",
+COMPARED = ["name", "role", "datatype", "description",
             "id", "path", "checksum", "size"]
 
 
@@ -673,6 +673,45 @@ def compare_entities(old_entity: Entity, new_entity: Entity):
     return (olddiff, newdiff)
 
 
+def copy_entity(entity: Entity):
+    """
+    Return a copy of entity.
+
+    If deep == True return a deep copy, recursively copying all sub entities.
+    """
+    print(entity)
+    if entity.role == "File":
+        new = File()
+    elif entity.role == "Property":
+        new = Property()
+    elif entity.role == "RecordType":
+        new = RecordType()
+    elif entity.role == "Record":
+        new = Record()
+    elif entity.role == "Entity":
+        new = Entity()
+    else:
+        raise RuntimeError("Unkonwn role.")
+
+    # Copy special attributes:
+    # TODO: this might rise an exception when copying
+    #       special file attributes like checksum and size.
+    for attribute in COMPARED + ["value"]:
+        val = getattr(entity, attribute)
+        if val is not None:
+            setattr(new, attribute, val)
+
+    # Copy parents:
+    for p in entity.parents:
+        new.add_parent(p)
+
+    # Copy properties:
+    for p in entity.properties:
+        new.add_property(p, importance=entity.get_importance(p))
+
+    return new
+
+
 def describe_diff(olddiff, newdiff, name=None, as_update=True):
     description = ""
 
diff --git a/unittests/test_apiutils.py b/unittests/test_apiutils.py
index 0294646f..6ce53a24 100644
--- a/unittests/test_apiutils.py
+++ b/unittests/test_apiutils.py
@@ -31,7 +31,7 @@ import tempfile
 import caosdb as db
 import caosdb.apiutils
 from caosdb.apiutils import (apply_to_ids, compare_entities, create_id_query,
-                             resolve_reference)
+                             resolve_reference, copy_entity, merge_entities)
 
 from .test_property import testrecord
 
@@ -230,3 +230,23 @@ def test_compare_special_properties():
             assert diff_r2[key] == 2
         assert len(diff_r1["properties"]) == 0
         assert len(diff_r2["properties"]) == 0
+
+def test_copy_entities():
+    r = db.Record(name="A")
+    r.add_parent(name="B")
+    r.add_property(name="C", value=4, importance="OBLIGATORY")
+    r.add_property(name="D", value=[3, 4, 7], importance="OBLIGATORY")
+    r.description = "A fancy test record"
+
+    c = copy_entity(r)
+
+    assert c != r
+    assert c.name == "A"
+    assert c.parents[0].name == "B"
+    # Currently parents and properties are always individual to a copy:
+    assert c.parents[0] != r.parents[0]
+
+    for i in [0, 1]:
+        assert c.properties[i] != r.properties[i]
+        assert c.properties[i].value == r.properties[i].value
+        assert c.get_importance(c.properties[i]) == r.get_importance(r.properties[i])
-- 
GitLab