Skip to content
Snippets Groups Projects
Commit e066c47f authored by Henrik tom Wörden's avatar Henrik tom Wörden
Browse files

MAINT: introduce the Identifiable class

parent 29f8b748
Branches
Tags
2 merge requests!91Release 0.3,!8backref
Pipeline #30412 failed
......@@ -33,6 +33,16 @@ from .utils import has_parent
logger = logging.getLogger(__name__)
def class Identifiable():
def __init__(self, record_type, name=None, properties=None, backrefs=None):
self.record_type = record_type
self.name = name
if properties is None:
self.properties = []
if backrefs is None:
self.backrefs = []
def convert_value(value):
""" Returns a string representation of the value that is suitable
to be used in the query
......@@ -86,7 +96,7 @@ class IdentifiableAdapter(metaclass=ABCMeta):
"""
@staticmethod
def create_query_for_identifiable(ident: db.Record):
def create_query_for_identifiable(ident: Identifiable):
"""
This function is taken from the old crawler:
caosdb-advanced-user-tools/src/caosadvancedtools/crawler.py
......@@ -94,41 +104,29 @@ class IdentifiableAdapter(metaclass=ABCMeta):
uses the properties of ident to create a query that can determine
whether the required record already exists.
"""
if len(ident.parents) != 1:
raise RuntimeError(
"Multiple parents for identifiables not supported.")
query_string = "FIND Record " + ident.get_parents()[0].name
if ident.get_property("is_referenced_by") is not None:
query_string += (" WHICH IS REFERENCED BY "
+ ident.get_property("is_referenced_by").value + " AND")
query_string = "FIND Record " + ident.record_type
for ref in ident.backrefs:
query_string += (" WHICH IS REFERENCED BY " + ref + " AND")
query_string += " WITH "
if ident.name is None and len(ident.get_properties()) == 0:
raise ValueError(
"The identifiable must have features to identify it.")
if ident.name is not None:
query_string += "name='{}'".format(ident.name)
if len(ident.get_properties()) > 0:
if len(ident.properties) > 0:
query_string += " AND "
query_string += IdentifiableAdapter.create_property_query(ident)
return query_string
@staticmethod
def create_property_query(entity: db.Entity):
def create_property_query(entity: Identifiable):
query_string = ""
for p in entity.get_properties():
if p.name == "is_referenced_by":
continue
elif p.value is None:
query_string += "'" + p.name + "' IS NULL AND "
elif isinstance(p.value, list):
for v in p.value:
query_string += ("'" + p.name + "'='" +
for pname, pvalue in entity.properties.items():
if pvalue is None:
query_string += "'" + pname + "' IS NULL AND "
elif isinstance(pvalue, list):
for v in pvalue:
query_string += ("'" + pname + "'='" +
convert_value(v) + "' AND ")
# TODO: (for review)
......@@ -142,8 +140,8 @@ class IdentifiableAdapter(metaclass=ABCMeta):
# IdentifiableAdapter.create_property_query(p.value) +
# ") AND ")
else:
query_string += ("'" + p.name + "'='" +
convert_value(p.value) + "' AND ")
query_string += ("'" + pname + "'='" +
convert_value(pvalue) + "' AND ")
# remove the last AND
return query_string[:-4]
......@@ -185,8 +183,6 @@ class IdentifiableAdapter(metaclass=ABCMeta):
identifiable.path = record.path
return identifiable
# -------------------------
# TODO: Review usage of referencing_entities
def get_identifiable(self, record: db.Record, referencing_entities=None):
"""
retrieve the registred identifiable and fill the property values to create an
......@@ -196,24 +192,19 @@ class IdentifiableAdapter(metaclass=ABCMeta):
if record.role == "File":
return self.get_identifiable_for_file(record)
# TODO: refactoring for backref
# Change this function to return a new datastructure (object) containting:
# a list of properties
# the parent name
# a (list of) backref(s)
registered_identifiable = self.get_registered_identifiable(record)
if registered_identifiable is None:
return None
if referencing_entities is None:
referencing_entities = {}
identifiable = db.Record(name=record.name)
if len(registered_identifiable.parents) != 1:
raise RuntimeError("Multiple parents for identifiables"
"not supported.")
identifiable.add_parent(registered_identifiable.parents[0])
property_name_list_A = []
property_name_list_B = []
identifiable_props = {}
identifiable_backrefs = []
# fill the values:
for prop in registered_identifiable.properties:
......@@ -230,7 +221,7 @@ class IdentifiableAdapter(metaclass=ABCMeta):
rtname = self.get_recordtype_name(prop.value)
if (id(record) in referencing_entities
and rtname in referencing_entities[id(record)]):
identifiable.add_property("is_referenced_by", referencing_entities[rtname])
identifiable_backrefs.append(referencing_entities[rtname])
continue
record_prop = record.get_property(prop.name)
if record_prop is None:
......@@ -240,14 +231,7 @@ class IdentifiableAdapter(metaclass=ABCMeta):
f"The following record is missing an identifying property:"
f"RECORD\n{record}\nIdentifying PROPERTY\n{prop.name}"
)
newval = record_prop.value
record_prop_new = db.Property(name=record_prop.name,
id=record_prop.id,
description=record_prop.description,
datatype=record_prop.datatype,
value=newval,
unit=record_prop.unit)
identifiable.add_property(record_prop_new)
identifiable_props[record_prop.name] = record_prop.value
property_name_list_A.append(prop.name)
# check for multi properties in the record:
......@@ -258,7 +242,11 @@ class IdentifiableAdapter(metaclass=ABCMeta):
raise RuntimeError(
"Multi properties used in identifiables can cause unpredictable results.")
return identifiable
return Identifiable(registered_identifiable.parents[0],
name=record.name,
properties=identifiable_props,
backrefs=identifiable_backrefs
)
@abstractmethod
def retrieve_identified_record_for_identifiable(self, identifiable: db.Record,
......@@ -292,8 +280,7 @@ class IdentifiableAdapter(metaclass=ABCMeta):
if identifiable.role == "File":
return self.get_file(identifiable)
return self.retrieve_identified_record_for_identifiable(
identifiable, referencing_entities=referencing_entities)
return self.retrieve_identified_record_for_identifiable(identifiable)
class LocalStorageIdentifiableAdapter(IdentifiableAdapter):
......@@ -404,8 +391,7 @@ class LocalStorageIdentifiableAdapter(IdentifiableAdapter):
return False
return True
def retrieve_identified_record_for_identifiable(self, identifiable:
db.Record, referencing_entities=None):
def retrieve_identified_record_for_identifiable(self, identifiable: Identifiable):
candidates = []
for record in self._records:
if self.check_record(record, identifiable):
......@@ -490,9 +476,8 @@ class CaosDBIdentifiableAdapter(IdentifiableAdapter):
return record
return record.id
def retrieve_identified_record_for_identifiable(self, identifiable: db.Record,
referencing_entities=None):
query_string = self.create_query_for_identifiable(identifiable, referencing_entities)
def retrieve_identified_record_for_identifiable(self, identifiable: Identifiable):
query_string = self.create_query_for_identifiable(identifiable)
candidates = db.execute_query(query_string)
if len(candidates) > 1:
raise RuntimeError(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment