"""_____________________________________________________________________

:PROJECT: LARAsuite

*lara_django_projects high_level_interface *

:details: lara_django_projects high_level_interface.
         - generated with 'lara-django-dev generate_high_level_interface lara_django_projects
:authors: mark doerr <mark.doerr@uni-greifswald.de>

.. note:: -
.. todo:: -
________________________________________________________________________
"""

import json
import asyncio
import logging
import grpc
from typing import Union

from google.protobuf.json_format import MessageToDict

import lara_django_base_grpc.v1.lara_django_base_pb2 as lara_django_base_pb2
import lara_django_base_grpc.v1.lara_django_base_pb2_grpc as lara_django_base_pb2_grpc

import lara_django_projects_grpc.v1.lara_django_projects_pb2 as lara_django_projects_pb2
import lara_django_projects_grpc.v1.lara_django_projects_pb2_grpc as lara_django_projects_pb2_grpc

import  lara_django_base_grpc.lara_django_base_data_model as base_dm
import  lara_django_base_grpc.lara_django_base_interface as base_if
from  lara_django_base_grpc.abstract_interface import LARAInterface, GRPCChannelSingleton, import_model_instance_from_file, export_model_instance_to_file, upload_file, download_file, update_file, upload_image, update_image, download_image, id_cache

import  lara_django_projects_grpc.lara_django_projects_data_model as projects_dm

logger = logging.getLogger(__name__)



#_________________  Task  ______________________


class TaskInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.task_class_client = (
        #     lara_django_projects_pb2_grpc.TaskclassByIRIControllerStub(channel)
        # )

        self.task_client = lara_django_projects_pb2_grpc.TaskControllerStub(channel)


        # self.task_full_client = lara_django_projects_pb2_grpc.TaskFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  tasks:  list[projects_dm.Task] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.Task]]:
        """ create a list of task instances,
               returns a list of task data model objects or ids_only

        :param tasks: list of task data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of task data model objects or ids_only
        """
        taskclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if task_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.task_class_client.Retrieve(
        #         lara_django_projects_pb2.TaskclassRetrieveRequest(iri=task_class_iri)
        #     )
        #     taskclass_id = res.taskclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving taskclass_id: {e}")
        for task in tasks:
            if self._default_namespace_id is not None:
                if task.namespace == "" or task.namespace == "default":
                    task.namespace = self._default_namespace_id
            # task.task_class = taskclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.task_client.Create(lara_django_projects_pb2.TaskRequest(**task.model_dump())) for task in tasks )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.task_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating task: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        task_id: str = None,
        task_name: str = None,
        #task_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.Task]:
        """ retrieve a list of task instances by task_id, task_name or filter_dict,
               returns a list of task data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and task_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  task_id is not None:
            try:
                res =  await self.task_client.Retrieve(
                    lara_django_projects_pb2.TaskRetrieveRequest(task_id=task_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.Task(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving task_id: {e}")

        if task_name is not None:
            filter_list.append({"name": task_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if task_name_display is not None:
        #     filter_list.append({"name_display": task_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.task_client.List(
                        lara_django_projects_pb2.TaskListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.Task(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving task_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          task_name: str = None,
                          task_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the task_id for a given task_name,
               task_name_display or iri
        """
        if task_name is not None:
            filter_dict = {"name": task_name}
        elif task_name_display is not None:
            filter_dict = {"name_display": task_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.task_client.List(
                lara_django_projects_pb2.TaskListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving task_name: {e}")
        if len(results) == 1 :
            return results[0].task_id
        else:
            raise ValueError(f"Error retrieving task_id - no or too many results found.")

    async def get_by_id(self, task_id: str = None) -> projects_dm.Task:
        """ retrieve a task data model by task_id """
        try:
            res = await self.task_client.Retrieve(
                lara_django_projects_pb2.TaskRetrieveRequest(task_id=task_id)
            )
            return projects_dm.Task(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving task_id: {e}")

    async def get_by_name(self, task_name: str = None,
                                namespace_uri : str = None) -> projects_dm.Task:
        """ retrieve a task data model by task_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.task_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.TaskRetrieveByNameNSRequest(name=task_name, namespace_uri=namespace_uri)
            )
            return projects_dm.Task(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving task_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all tasks """
        if filter_dict is None:
            res = await self.task_client.List(lara_django_projects_pb2.TaskListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.task_client.List(
                lara_django_projects_pb2.TaskListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.task_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all tasks """
        if self.task_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.task_full_client.List(
                lara_django_projects_pb2.TaskFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.task_full_client.List(
                lara_django_projects_pb2.TaskFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, task : projects_dm.Task = None) -> None:
        """ update a task model instance """
        try:
            await self.task_client.Update(
                lara_django_projects_pb2.TaskRequest(**task.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating task_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a task by task_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.task_client.Destroy(lara_django_projects_pb2.TaskDestroyRequest(task_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting task_id: {e}")

#_________________  Project  ______________________


class ProjectInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.project_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectclassByIRIControllerStub(channel)
        # )

        self.project_client = lara_django_projects_pb2_grpc.ProjectControllerStub(channel)


        # self.project_full_client = lara_django_projects_pb2_grpc.ProjectFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  projects:  list[projects_dm.Project] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.Project]]:
        """ create a list of project instances,
               returns a list of project data model objects or ids_only

        :param projects: list of project data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of project data model objects or ids_only
        """
        projectclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if project_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.project_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectclassRetrieveRequest(iri=project_class_iri)
        #     )
        #     projectclass_id = res.projectclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving projectclass_id: {e}")
        for project in projects:
            if self._default_namespace_id is not None:
                if project.namespace == "" or project.namespace == "default":
                    project.namespace = self._default_namespace_id
            # project.project_class = projectclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.project_client.Create(lara_django_projects_pb2.ProjectRequest(**project.model_dump())) for project in projects )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.project_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating project: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        project_id: str = None,
        project_name: str = None,
        #project_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.Project]:
        """ retrieve a list of project instances by project_id, project_name or filter_dict,
               returns a list of project data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and project_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  project_id is not None:
            try:
                res =  await self.project_client.Retrieve(
                    lara_django_projects_pb2.ProjectRetrieveRequest(project_id=project_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving project_id: {e}")

        if project_name is not None:
            filter_list.append({"name": project_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if project_name_display is not None:
        #     filter_list.append({"name_display": project_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.project_client.List(
                        lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving project_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          project_name: str = None,
                          project_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the project_id for a given project_name,
               project_name_display or iri
        """
        if project_name is not None:
            filter_dict = {"name": project_name}
        elif project_name_display is not None:
            filter_dict = {"name_display": project_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.project_client.List(
                lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving project_name: {e}")
        if len(results) == 1 :
            return results[0].project_id
        else:
            raise ValueError(f"Error retrieving project_id - no or too many results found.")

    async def get_by_id(self, project_id: str = None) -> projects_dm.Project:
        """ retrieve a project data model by project_id """
        try:
            res = await self.project_client.Retrieve(
                lara_django_projects_pb2.ProjectRetrieveRequest(project_id=project_id)
            )
            return projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving project_id: {e}")

    async def get_by_name(self, project_name: str = None,
                                namespace_uri : str = None) -> projects_dm.Project:
        """ retrieve a project data model by project_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.project_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ProjectRetrieveByNameNSRequest(name=project_name, namespace_uri=namespace_uri)
            )
            return projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving project_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all projects """
        if filter_dict is None:
            res = await self.project_client.List(lara_django_projects_pb2.ProjectListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.project_client.List(
                lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.project_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all projects """
        if self.project_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.project_full_client.List(
                lara_django_projects_pb2.ProjectFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.project_full_client.List(
                lara_django_projects_pb2.ProjectFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, project : projects_dm.Project = None) -> None:
        """ update a project model instance """
        try:
            await self.project_client.Update(
                lara_django_projects_pb2.ProjectRequest(**project.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating project_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a project by project_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.project_client.Destroy(lara_django_projects_pb2.ProjectDestroyRequest(project_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting project_id: {e}")

#_________________  RoledProjectEntities  ______________________


class RoledProjectEntitiesInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.roledprojectentities_client = lara_django_projects_pb2_grpc.RoledProjectEntitiesControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  roledprojectentitiess:  list[projects_dm.RoledProjectEntities] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.RoledProjectEntities]]:
        try:
            create_coroutines = ( self.roledprojectentities_client.Create(lara_django_projects_pb2.RoledProjectEntitiesRequest(**roledprojectentities.model_dump())) for roledprojectentities in roledprojectentitiess )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.roledprojectentities_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating roledprojectentities: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        roledprojectentities_id: str = None,
        roledprojectentities_name: str = None,
        #roledprojectentities_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.RoledProjectEntities]:
        """ retrieve a list of roledprojectentities instances by roledprojectentities_id, roledprojectentities_name or filter_dict,
               returns a list of roledprojectentities data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  roledprojectentities_id is not None:
            try:
                res =  await self.roledprojectentities_client.Retrieve(
                    lara_django_projects_pb2.RoledProjectEntitiesRetrieveRequest(roledprojectentities_id=roledprojectentities_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.RoledProjectEntities(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving roledprojectentities_id: {e}")

        if roledprojectentities_name is not None:
            filter_list.append({"name": roledprojectentities_name})
        # if roledprojectentities_name_display is not None:
        #     filter_list.append({"name_display": roledprojectentities_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.roledprojectentities_client.List(
                        lara_django_projects_pb2.RoledProjectEntitiesListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.RoledProjectEntities(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving roledprojectentities_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          roledprojectentities_name: str = None,
                          roledprojectentities_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the roledprojectentities_id for a given roledprojectentities_name,
               roledprojectentities_name_display or iri
        """
        if roledprojectentities_name is not None:
            filter_dict = {"name": roledprojectentities_name}
        elif roledprojectentities_name_display is not None:
            filter_dict = {"name_display": roledprojectentities_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.roledprojectentities_client.List(
                lara_django_projects_pb2.RoledProjectEntitiesListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving roledprojectentities_name: {e}")
        if len(results) == 1 :
            return results[0].roledprojectentities_id
        else:
            raise ValueError(f"Error retrieving roledprojectentities_id - no or too many results found.")

    async def get_by_id(self, roledprojectentities_id: str = None) -> projects_dm.RoledProjectEntities:
        """ retrieve a roledprojectentities data model by roledprojectentities_id """
        try:
            res = await self.roledprojectentities_client.Retrieve(
                lara_django_projects_pb2.RoledProjectEntitiesRetrieveRequest(roledprojectentities_id=roledprojectentities_id)
            )
            return projects_dm.RoledProjectEntities(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving roledprojectentities_id: {e}")

    async def get_by_name(self, roledprojectentities_name: str = None) -> projects_dm.RoledProjectEntities:
        """ retrieve a roledprojectentities data model by roledprojectentities_name """
        try:
            res = await self.roledprojectentities_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.RoledProjectEntitiesRetrieveByNameNSRequest(name=roledprojectentities_name, namespace_uri="")
            )
            return projects_dm.RoledProjectEntities(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving roledprojectentities_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all roledprojectentitiess """
        if filter_dict is None:
            res = await self.roledprojectentities_client.List(lara_django_projects_pb2.RoledProjectEntitiesListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.roledprojectentities_client.List(
                lara_django_projects_pb2.RoledProjectEntitiesListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.roledprojectentities_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all roledprojectentitiess """
        if self.roledprojectentities_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.roledprojectentities_full_client.List(
                lara_django_projects_pb2.RoledProjectEntitiesFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.roledprojectentities_full_client.List(
                lara_django_projects_pb2.RoledProjectEntitiesFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, roledprojectentities : projects_dm.RoledProjectEntities = None) -> None:
        """ update a roledprojectentities model instance """
        try:
            await self.roledprojectentities_client.Update(
                lara_django_projects_pb2.RoledProjectEntitiesRequest(**roledprojectentities.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating roledprojectentities_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a roledprojectentities by roledprojectentities_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.roledprojectentities_client.Destroy(lara_django_projects_pb2.RoledProjectEntitiesDestroyRequest(roledprojectentities_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting roledprojectentities_id: {e}")

#_________________  ProjectsSubset  ______________________


class ProjectsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectssubset_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectsSubsetclassByIRIControllerStub(channel)
        # )

        self.projectssubset_client = lara_django_projects_pb2_grpc.ProjectsSubsetControllerStub(channel)


        # self.projectssubset_full_client = lara_django_projects_pb2_grpc.ProjectsSubsetFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  projectssubsets:  list[projects_dm.ProjectsSubset] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ProjectsSubset]]:
        """ create a list of projectssubset instances,
               returns a list of projectssubset data model objects or ids_only

        :param projectssubsets: list of projectssubset data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of projectssubset data model objects or ids_only
        """
        projectssubsetclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectssubset_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectssubset_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectsSubsetclassRetrieveRequest(iri=projectssubset_class_iri)
        #     )
        #     projectssubsetclass_id = res.projectssubsetclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving projectssubsetclass_id: {e}")
        for projectssubset in projectssubsets:
            if self._default_namespace_id is not None:
                if projectssubset.namespace == "" or projectssubset.namespace == "default":
                    projectssubset.namespace = self._default_namespace_id
            # projectssubset.projectssubset_class = projectssubsetclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.projectssubset_client.Create(lara_django_projects_pb2.ProjectsSubsetRequest(**projectssubset.model_dump())) for projectssubset in projectssubsets )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectssubset_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating projectssubset: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        projectssubset_id: str = None,
        projectssubset_name: str = None,
        #projectssubset_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectsSubset]:
        """ retrieve a list of projectssubset instances by projectssubset_id, projectssubset_name or filter_dict,
               returns a list of projectssubset data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and projectssubset_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  projectssubset_id is not None:
            try:
                res =  await self.projectssubset_client.Retrieve(
                    lara_django_projects_pb2.ProjectsSubsetRetrieveRequest(projectssubset_id=projectssubset_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving projectssubset_id: {e}")

        if projectssubset_name is not None:
            filter_list.append({"name": projectssubset_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if projectssubset_name_display is not None:
        #     filter_list.append({"name_display": projectssubset_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectssubset_client.List(
                        lara_django_projects_pb2.ProjectsSubsetListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving projectssubset_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          projectssubset_name: str = None,
                          projectssubset_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the projectssubset_id for a given projectssubset_name,
               projectssubset_name_display or iri
        """
        if projectssubset_name is not None:
            filter_dict = {"name": projectssubset_name}
        elif projectssubset_name_display is not None:
            filter_dict = {"name_display": projectssubset_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.projectssubset_client.List(
                lara_django_projects_pb2.ProjectsSubsetListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving projectssubset_name: {e}")
        if len(results) == 1 :
            return results[0].projectssubset_id
        else:
            raise ValueError(f"Error retrieving projectssubset_id - no or too many results found.")

    async def get_by_id(self, projectssubset_id: str = None) -> projects_dm.ProjectsSubset:
        """ retrieve a projectssubset data model by projectssubset_id """
        try:
            res = await self.projectssubset_client.Retrieve(
                lara_django_projects_pb2.ProjectsSubsetRetrieveRequest(projectssubset_id=projectssubset_id)
            )
            return projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectssubset_id: {e}")

    async def get_by_name(self, projectssubset_name: str = None,
                                namespace_uri : str = None) -> projects_dm.ProjectsSubset:
        """ retrieve a projectssubset data model by projectssubset_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.projectssubset_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ProjectsSubsetRetrieveByNameNSRequest(name=projectssubset_name, namespace_uri=namespace_uri)
            )
            return projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectssubset_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all projectssubsets """
        if filter_dict is None:
            res = await self.projectssubset_client.List(lara_django_projects_pb2.ProjectsSubsetListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectssubset_client.List(
                lara_django_projects_pb2.ProjectsSubsetListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectssubset_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all projectssubsets """
        if self.projectssubset_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectssubset_full_client.List(
                lara_django_projects_pb2.ProjectsSubsetFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectssubset_full_client.List(
                lara_django_projects_pb2.ProjectsSubsetFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, projectssubset : projects_dm.ProjectsSubset = None) -> None:
        """ update a projectssubset model instance """
        try:
            await self.projectssubset_client.Update(
                lara_django_projects_pb2.ProjectsSubsetRequest(**projectssubset.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating projectssubset_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a projectssubset by projectssubset_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.projectssubset_client.Destroy(lara_django_projects_pb2.ProjectsSubsetDestroyRequest(projectssubset_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting projectssubset_id: {e}")

#_________________  OrderedProjectsProjectsSubset  ______________________


class OrderedProjectsProjectsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.orderedprojectsprojectssubset_client = lara_django_projects_pb2_grpc.OrderedProjectsProjectsSubsetControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  orderedprojectsprojectssubsets:  list[projects_dm.OrderedProjectsProjectsSubset] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.OrderedProjectsProjectsSubset]]:
        try:
            create_coroutines = ( self.orderedprojectsprojectssubset_client.Create(lara_django_projects_pb2.OrderedProjectsProjectsSubsetRequest(**orderedprojectsprojectssubset.model_dump())) for orderedprojectsprojectssubset in orderedprojectsprojectssubsets )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.orderedprojectsprojectssubset_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating orderedprojectsprojectssubset: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        orderedprojectsprojectssubset_id: str = None,
        orderedprojectsprojectssubset_name: str = None,
        #orderedprojectsprojectssubset_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.OrderedProjectsProjectsSubset]:
        """ retrieve a list of orderedprojectsprojectssubset instances by orderedprojectsprojectssubset_id, orderedprojectsprojectssubset_name or filter_dict,
               returns a list of orderedprojectsprojectssubset data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  orderedprojectsprojectssubset_id is not None:
            try:
                res =  await self.orderedprojectsprojectssubset_client.Retrieve(
                    lara_django_projects_pb2.OrderedProjectsProjectsSubsetRetrieveRequest(orderedprojectsprojectssubset_id=orderedprojectsprojectssubset_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.OrderedProjectsProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving orderedprojectsprojectssubset_id: {e}")

        if orderedprojectsprojectssubset_name is not None:
            filter_list.append({"name": orderedprojectsprojectssubset_name})
        # if orderedprojectsprojectssubset_name_display is not None:
        #     filter_list.append({"name_display": orderedprojectsprojectssubset_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.orderedprojectsprojectssubset_client.List(
                        lara_django_projects_pb2.OrderedProjectsProjectsSubsetListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.OrderedProjectsProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving orderedprojectsprojectssubset_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          orderedprojectsprojectssubset_name: str = None,
                          orderedprojectsprojectssubset_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the orderedprojectsprojectssubset_id for a given orderedprojectsprojectssubset_name,
               orderedprojectsprojectssubset_name_display or iri
        """
        if orderedprojectsprojectssubset_name is not None:
            filter_dict = {"name": orderedprojectsprojectssubset_name}
        elif orderedprojectsprojectssubset_name_display is not None:
            filter_dict = {"name_display": orderedprojectsprojectssubset_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.orderedprojectsprojectssubset_client.List(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving orderedprojectsprojectssubset_name: {e}")
        if len(results) == 1 :
            return results[0].orderedprojectsprojectssubset_id
        else:
            raise ValueError(f"Error retrieving orderedprojectsprojectssubset_id - no or too many results found.")

    async def get_by_id(self, orderedprojectsprojectssubset_id: str = None) -> projects_dm.OrderedProjectsProjectsSubset:
        """ retrieve a orderedprojectsprojectssubset data model by orderedprojectsprojectssubset_id """
        try:
            res = await self.orderedprojectsprojectssubset_client.Retrieve(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetRetrieveRequest(orderedprojectsprojectssubset_id=orderedprojectsprojectssubset_id)
            )
            return projects_dm.OrderedProjectsProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving orderedprojectsprojectssubset_id: {e}")

    async def get_by_name(self, orderedprojectsprojectssubset_name: str = None) -> projects_dm.OrderedProjectsProjectsSubset:
        """ retrieve a orderedprojectsprojectssubset data model by orderedprojectsprojectssubset_name """
        try:
            res = await self.orderedprojectsprojectssubset_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetRetrieveByNameNSRequest(name=orderedprojectsprojectssubset_name, namespace_uri="")
            )
            return projects_dm.OrderedProjectsProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving orderedprojectsprojectssubset_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all orderedprojectsprojectssubsets """
        if filter_dict is None:
            res = await self.orderedprojectsprojectssubset_client.List(lara_django_projects_pb2.OrderedProjectsProjectsSubsetListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.orderedprojectsprojectssubset_client.List(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.orderedprojectsprojectssubset_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all orderedprojectsprojectssubsets """
        if self.orderedprojectsprojectssubset_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.orderedprojectsprojectssubset_full_client.List(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.orderedprojectsprojectssubset_full_client.List(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, orderedprojectsprojectssubset : projects_dm.OrderedProjectsProjectsSubset = None) -> None:
        """ update a orderedprojectsprojectssubset model instance """
        try:
            await self.orderedprojectsprojectssubset_client.Update(
                lara_django_projects_pb2.OrderedProjectsProjectsSubsetRequest(**orderedprojectsprojectssubset.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating orderedprojectsprojectssubset_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a orderedprojectsprojectssubset by orderedprojectsprojectssubset_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.orderedprojectsprojectssubset_client.Destroy(lara_django_projects_pb2.OrderedProjectsProjectsSubsetDestroyRequest(orderedprojectsprojectssubset_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting orderedprojectsprojectssubset_id: {e}")

#_________________  Experiment  ______________________


class ExperimentInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.experiment_class_client = (
        #     lara_django_projects_pb2_grpc.ExperimentclassByIRIControllerStub(channel)
        # )

        self.experiment_client = lara_django_projects_pb2_grpc.ExperimentControllerStub(channel)


        # self.experiment_full_client = lara_django_projects_pb2_grpc.ExperimentFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  experiments:  list[projects_dm.Experiment] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.Experiment]]:
        """ create a list of experiment instances,
               returns a list of experiment data model objects or ids_only

        :param experiments: list of experiment data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of experiment data model objects or ids_only
        """
        experimentclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if experiment_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.experiment_class_client.Retrieve(
        #         lara_django_projects_pb2.ExperimentclassRetrieveRequest(iri=experiment_class_iri)
        #     )
        #     experimentclass_id = res.experimentclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving experimentclass_id: {e}")
        for experiment in experiments:
            if self._default_namespace_id is not None:
                if experiment.namespace == "" or experiment.namespace == "default":
                    experiment.namespace = self._default_namespace_id
            # experiment.experiment_class = experimentclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.experiment_client.Create(lara_django_projects_pb2.ExperimentRequest(**experiment.model_dump())) for experiment in experiments )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experiment_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating experiment: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        experiment_id: str = None,
        experiment_name: str = None,
        #experiment_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.Experiment]:
        """ retrieve a list of experiment instances by experiment_id, experiment_name or filter_dict,
               returns a list of experiment data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and experiment_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  experiment_id is not None:
            try:
                res =  await self.experiment_client.Retrieve(
                    lara_django_projects_pb2.ExperimentRetrieveRequest(experiment_id=experiment_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving experiment_id: {e}")

        if experiment_name is not None:
            filter_list.append({"name": experiment_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if experiment_name_display is not None:
        #     filter_list.append({"name_display": experiment_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experiment_client.List(
                        lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving experiment_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          experiment_name: str = None,
                          experiment_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the experiment_id for a given experiment_name,
               experiment_name_display or iri
        """
        if experiment_name is not None:
            filter_dict = {"name": experiment_name}
        elif experiment_name_display is not None:
            filter_dict = {"name_display": experiment_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.experiment_client.List(
                lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving experiment_name: {e}")
        if len(results) == 1 :
            return results[0].experiment_id
        else:
            raise ValueError(f"Error retrieving experiment_id - no or too many results found.")

    async def get_by_id(self, experiment_id: str = None) -> projects_dm.Experiment:
        """ retrieve a experiment data model by experiment_id """
        try:
            res = await self.experiment_client.Retrieve(
                lara_django_projects_pb2.ExperimentRetrieveRequest(experiment_id=experiment_id)
            )
            return projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experiment_id: {e}")

    async def get_by_name(self, experiment_name: str = None,
                                namespace_uri : str = None) -> projects_dm.Experiment:
        """ retrieve a experiment data model by experiment_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.experiment_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ExperimentRetrieveByNameNSRequest(name=experiment_name, namespace_uri=namespace_uri)
            )
            return projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experiment_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all experiments """
        if filter_dict is None:
            res = await self.experiment_client.List(lara_django_projects_pb2.ExperimentListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experiment_client.List(
                lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experiment_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all experiments """
        if self.experiment_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experiment_full_client.List(
                lara_django_projects_pb2.ExperimentFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experiment_full_client.List(
                lara_django_projects_pb2.ExperimentFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, experiment : projects_dm.Experiment = None) -> None:
        """ update a experiment model instance """
        try:
            await self.experiment_client.Update(
                lara_django_projects_pb2.ExperimentRequest(**experiment.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating experiment_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a experiment by experiment_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.experiment_client.Destroy(lara_django_projects_pb2.ExperimentDestroyRequest(experiment_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting experiment_id: {e}")

#_________________  RoledExperimentEntities  ______________________


class RoledExperimentEntitiesInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.roledexperimententities_client = lara_django_projects_pb2_grpc.RoledExperimentEntitiesControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  roledexperimententitiess:  list[projects_dm.RoledExperimentEntities] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.RoledExperimentEntities]]:
        try:
            create_coroutines = ( self.roledexperimententities_client.Create(lara_django_projects_pb2.RoledExperimentEntitiesRequest(**roledexperimententities.model_dump())) for roledexperimententities in roledexperimententitiess )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.roledexperimententities_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating roledexperimententities: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        roledexperimententities_id: str = None,
        roledexperimententities_name: str = None,
        #roledexperimententities_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.RoledExperimentEntities]:
        """ retrieve a list of roledexperimententities instances by roledexperimententities_id, roledexperimententities_name or filter_dict,
               returns a list of roledexperimententities data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  roledexperimententities_id is not None:
            try:
                res =  await self.roledexperimententities_client.Retrieve(
                    lara_django_projects_pb2.RoledExperimentEntitiesRetrieveRequest(roledexperimententities_id=roledexperimententities_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.RoledExperimentEntities(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving roledexperimententities_id: {e}")

        if roledexperimententities_name is not None:
            filter_list.append({"name": roledexperimententities_name})
        # if roledexperimententities_name_display is not None:
        #     filter_list.append({"name_display": roledexperimententities_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.roledexperimententities_client.List(
                        lara_django_projects_pb2.RoledExperimentEntitiesListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.RoledExperimentEntities(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving roledexperimententities_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          roledexperimententities_name: str = None,
                          roledexperimententities_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the roledexperimententities_id for a given roledexperimententities_name,
               roledexperimententities_name_display or iri
        """
        if roledexperimententities_name is not None:
            filter_dict = {"name": roledexperimententities_name}
        elif roledexperimententities_name_display is not None:
            filter_dict = {"name_display": roledexperimententities_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.roledexperimententities_client.List(
                lara_django_projects_pb2.RoledExperimentEntitiesListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving roledexperimententities_name: {e}")
        if len(results) == 1 :
            return results[0].roledexperimententities_id
        else:
            raise ValueError(f"Error retrieving roledexperimententities_id - no or too many results found.")

    async def get_by_id(self, roledexperimententities_id: str = None) -> projects_dm.RoledExperimentEntities:
        """ retrieve a roledexperimententities data model by roledexperimententities_id """
        try:
            res = await self.roledexperimententities_client.Retrieve(
                lara_django_projects_pb2.RoledExperimentEntitiesRetrieveRequest(roledexperimententities_id=roledexperimententities_id)
            )
            return projects_dm.RoledExperimentEntities(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving roledexperimententities_id: {e}")

    async def get_by_name(self, roledexperimententities_name: str = None) -> projects_dm.RoledExperimentEntities:
        """ retrieve a roledexperimententities data model by roledexperimententities_name """
        try:
            res = await self.roledexperimententities_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.RoledExperimentEntitiesRetrieveByNameNSRequest(name=roledexperimententities_name, namespace_uri="")
            )
            return projects_dm.RoledExperimentEntities(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving roledexperimententities_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all roledexperimententitiess """
        if filter_dict is None:
            res = await self.roledexperimententities_client.List(lara_django_projects_pb2.RoledExperimentEntitiesListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.roledexperimententities_client.List(
                lara_django_projects_pb2.RoledExperimentEntitiesListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.roledexperimententities_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all roledexperimententitiess """
        if self.roledexperimententities_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.roledexperimententities_full_client.List(
                lara_django_projects_pb2.RoledExperimentEntitiesFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.roledexperimententities_full_client.List(
                lara_django_projects_pb2.RoledExperimentEntitiesFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, roledexperimententities : projects_dm.RoledExperimentEntities = None) -> None:
        """ update a roledexperimententities model instance """
        try:
            await self.roledexperimententities_client.Update(
                lara_django_projects_pb2.RoledExperimentEntitiesRequest(**roledexperimententities.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating roledexperimententities_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a roledexperimententities by roledexperimententities_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.roledexperimententities_client.Destroy(lara_django_projects_pb2.RoledExperimentEntitiesDestroyRequest(roledexperimententities_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting roledexperimententities_id: {e}")

#_________________  ExperimentsSubset  ______________________


class ExperimentsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.experimentssubset_class_client = (
        #     lara_django_projects_pb2_grpc.ExperimentsSubsetclassByIRIControllerStub(channel)
        # )

        self.experimentssubset_client = lara_django_projects_pb2_grpc.ExperimentsSubsetControllerStub(channel)


        # self.experimentssubset_full_client = lara_django_projects_pb2_grpc.ExperimentsSubsetFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  experimentssubsets:  list[projects_dm.ExperimentsSubset] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ExperimentsSubset]]:
        """ create a list of experimentssubset instances,
               returns a list of experimentssubset data model objects or ids_only

        :param experimentssubsets: list of experimentssubset data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of experimentssubset data model objects or ids_only
        """
        experimentssubsetclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if experimentssubset_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.experimentssubset_class_client.Retrieve(
        #         lara_django_projects_pb2.ExperimentsSubsetclassRetrieveRequest(iri=experimentssubset_class_iri)
        #     )
        #     experimentssubsetclass_id = res.experimentssubsetclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving experimentssubsetclass_id: {e}")
        for experimentssubset in experimentssubsets:
            if self._default_namespace_id is not None:
                if experimentssubset.namespace == "" or experimentssubset.namespace == "default":
                    experimentssubset.namespace = self._default_namespace_id
            # experimentssubset.experimentssubset_class = experimentssubsetclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.experimentssubset_client.Create(lara_django_projects_pb2.ExperimentsSubsetRequest(**experimentssubset.model_dump())) for experimentssubset in experimentssubsets )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experimentssubset_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating experimentssubset: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        experimentssubset_id: str = None,
        experimentssubset_name: str = None,
        #experimentssubset_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ExperimentsSubset]:
        """ retrieve a list of experimentssubset instances by experimentssubset_id, experimentssubset_name or filter_dict,
               returns a list of experimentssubset data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and experimentssubset_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  experimentssubset_id is not None:
            try:
                res =  await self.experimentssubset_client.Retrieve(
                    lara_django_projects_pb2.ExperimentsSubsetRetrieveRequest(experimentssubset_id=experimentssubset_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving experimentssubset_id: {e}")

        if experimentssubset_name is not None:
            filter_list.append({"name": experimentssubset_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if experimentssubset_name_display is not None:
        #     filter_list.append({"name_display": experimentssubset_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentssubset_client.List(
                        lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving experimentssubset_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          experimentssubset_name: str = None,
                          experimentssubset_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the experimentssubset_id for a given experimentssubset_name,
               experimentssubset_name_display or iri
        """
        if experimentssubset_name is not None:
            filter_dict = {"name": experimentssubset_name}
        elif experimentssubset_name_display is not None:
            filter_dict = {"name_display": experimentssubset_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.experimentssubset_client.List(
                lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving experimentssubset_name: {e}")
        if len(results) == 1 :
            return results[0].experimentssubset_id
        else:
            raise ValueError(f"Error retrieving experimentssubset_id - no or too many results found.")

    async def get_by_id(self, experimentssubset_id: str = None) -> projects_dm.ExperimentsSubset:
        """ retrieve a experimentssubset data model by experimentssubset_id """
        try:
            res = await self.experimentssubset_client.Retrieve(
                lara_django_projects_pb2.ExperimentsSubsetRetrieveRequest(experimentssubset_id=experimentssubset_id)
            )
            return projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experimentssubset_id: {e}")

    async def get_by_name(self, experimentssubset_name: str = None,
                                namespace_uri : str = None) -> projects_dm.ExperimentsSubset:
        """ retrieve a experimentssubset data model by experimentssubset_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.experimentssubset_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ExperimentsSubsetRetrieveByNameNSRequest(name=experimentssubset_name, namespace_uri=namespace_uri)
            )
            return projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experimentssubset_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all experimentssubsets """
        if filter_dict is None:
            res = await self.experimentssubset_client.List(lara_django_projects_pb2.ExperimentsSubsetListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experimentssubset_client.List(
                lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experimentssubset_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all experimentssubsets """
        if self.experimentssubset_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experimentssubset_full_client.List(
                lara_django_projects_pb2.ExperimentsSubsetFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experimentssubset_full_client.List(
                lara_django_projects_pb2.ExperimentsSubsetFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, experimentssubset : projects_dm.ExperimentsSubset = None) -> None:
        """ update a experimentssubset model instance """
        try:
            await self.experimentssubset_client.Update(
                lara_django_projects_pb2.ExperimentsSubsetRequest(**experimentssubset.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating experimentssubset_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a experimentssubset by experimentssubset_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.experimentssubset_client.Destroy(lara_django_projects_pb2.ExperimentsSubsetDestroyRequest(experimentssubset_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting experimentssubset_id: {e}")

#_________________  OrderedExperimentsExperimentsSubset  ______________________


class OrderedExperimentsExperimentsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.orderedexperimentsexperimentssubset_client = lara_django_projects_pb2_grpc.OrderedExperimentsExperimentsSubsetControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  orderedexperimentsexperimentssubsets:  list[projects_dm.OrderedExperimentsExperimentsSubset] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.OrderedExperimentsExperimentsSubset]]:
        try:
            create_coroutines = ( self.orderedexperimentsexperimentssubset_client.Create(lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetRequest(**orderedexperimentsexperimentssubset.model_dump())) for orderedexperimentsexperimentssubset in orderedexperimentsexperimentssubsets )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.orderedexperimentsexperimentssubset_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating orderedexperimentsexperimentssubset: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        orderedexperimentsexperimentssubset_id: str = None,
        orderedexperimentsexperimentssubset_name: str = None,
        #orderedexperimentsexperimentssubset_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.OrderedExperimentsExperimentsSubset]:
        """ retrieve a list of orderedexperimentsexperimentssubset instances by orderedexperimentsexperimentssubset_id, orderedexperimentsexperimentssubset_name or filter_dict,
               returns a list of orderedexperimentsexperimentssubset data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  orderedexperimentsexperimentssubset_id is not None:
            try:
                res =  await self.orderedexperimentsexperimentssubset_client.Retrieve(
                    lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetRetrieveRequest(orderedexperimentsexperimentssubset_id=orderedexperimentsexperimentssubset_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.OrderedExperimentsExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving orderedexperimentsexperimentssubset_id: {e}")

        if orderedexperimentsexperimentssubset_name is not None:
            filter_list.append({"name": orderedexperimentsexperimentssubset_name})
        # if orderedexperimentsexperimentssubset_name_display is not None:
        #     filter_list.append({"name_display": orderedexperimentsexperimentssubset_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.orderedexperimentsexperimentssubset_client.List(
                        lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.OrderedExperimentsExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving orderedexperimentsexperimentssubset_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          orderedexperimentsexperimentssubset_name: str = None,
                          orderedexperimentsexperimentssubset_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the orderedexperimentsexperimentssubset_id for a given orderedexperimentsexperimentssubset_name,
               orderedexperimentsexperimentssubset_name_display or iri
        """
        if orderedexperimentsexperimentssubset_name is not None:
            filter_dict = {"name": orderedexperimentsexperimentssubset_name}
        elif orderedexperimentsexperimentssubset_name_display is not None:
            filter_dict = {"name_display": orderedexperimentsexperimentssubset_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.orderedexperimentsexperimentssubset_client.List(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving orderedexperimentsexperimentssubset_name: {e}")
        if len(results) == 1 :
            return results[0].orderedexperimentsexperimentssubset_id
        else:
            raise ValueError(f"Error retrieving orderedexperimentsexperimentssubset_id - no or too many results found.")

    async def get_by_id(self, orderedexperimentsexperimentssubset_id: str = None) -> projects_dm.OrderedExperimentsExperimentsSubset:
        """ retrieve a orderedexperimentsexperimentssubset data model by orderedexperimentsexperimentssubset_id """
        try:
            res = await self.orderedexperimentsexperimentssubset_client.Retrieve(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetRetrieveRequest(orderedexperimentsexperimentssubset_id=orderedexperimentsexperimentssubset_id)
            )
            return projects_dm.OrderedExperimentsExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving orderedexperimentsexperimentssubset_id: {e}")

    async def get_by_name(self, orderedexperimentsexperimentssubset_name: str = None) -> projects_dm.OrderedExperimentsExperimentsSubset:
        """ retrieve a orderedexperimentsexperimentssubset data model by orderedexperimentsexperimentssubset_name """
        try:
            res = await self.orderedexperimentsexperimentssubset_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetRetrieveByNameNSRequest(name=orderedexperimentsexperimentssubset_name, namespace_uri="")
            )
            return projects_dm.OrderedExperimentsExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving orderedexperimentsexperimentssubset_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all orderedexperimentsexperimentssubsets """
        if filter_dict is None:
            res = await self.orderedexperimentsexperimentssubset_client.List(lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.orderedexperimentsexperimentssubset_client.List(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.orderedexperimentsexperimentssubset_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all orderedexperimentsexperimentssubsets """
        if self.orderedexperimentsexperimentssubset_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.orderedexperimentsexperimentssubset_full_client.List(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.orderedexperimentsexperimentssubset_full_client.List(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, orderedexperimentsexperimentssubset : projects_dm.OrderedExperimentsExperimentsSubset = None) -> None:
        """ update a orderedexperimentsexperimentssubset model instance """
        try:
            await self.orderedexperimentsexperimentssubset_client.Update(
                lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetRequest(**orderedexperimentsexperimentssubset.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating orderedexperimentsexperimentssubset_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a orderedexperimentsexperimentssubset by orderedexperimentsexperimentssubset_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.orderedexperimentsexperimentssubset_client.Destroy(lara_django_projects_pb2.OrderedExperimentsExperimentsSubsetDestroyRequest(orderedexperimentsexperimentssubset_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting orderedexperimentsexperimentssubset_id: {e}")

#_________________  ProjectCalendar  ______________________


class ProjectCalendarInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.projectcalendar_client = lara_django_projects_pb2_grpc.ProjectCalendarControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  projectcalendars:  list[projects_dm.ProjectCalendar] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ProjectCalendar]]:
        try:
            create_coroutines = ( self.projectcalendar_client.Create(lara_django_projects_pb2.ProjectCalendarRequest(**projectcalendar.model_dump())) for projectcalendar in projectcalendars )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectcalendar_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating projectcalendar: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        projectcalendar_id: str = None,
        projectcalendar_name: str = None,
        #projectcalendar_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectCalendar]:
        """ retrieve a list of projectcalendar instances by projectcalendar_id, projectcalendar_name or filter_dict,
               returns a list of projectcalendar data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  projectcalendar_id is not None:
            try:
                res =  await self.projectcalendar_client.Retrieve(
                    lara_django_projects_pb2.ProjectCalendarRetrieveRequest(projectcalendar_id=projectcalendar_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving projectcalendar_id: {e}")

        if projectcalendar_name is not None:
            filter_list.append({"name": projectcalendar_name})
        # if projectcalendar_name_display is not None:
        #     filter_list.append({"name_display": projectcalendar_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectcalendar_client.List(
                        lara_django_projects_pb2.ProjectCalendarListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving projectcalendar_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          projectcalendar_name: str = None,
                          projectcalendar_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the projectcalendar_id for a given projectcalendar_name,
               projectcalendar_name_display or iri
        """
        if projectcalendar_name is not None:
            filter_dict = {"name": projectcalendar_name}
        elif projectcalendar_name_display is not None:
            filter_dict = {"name_display": projectcalendar_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.projectcalendar_client.List(
                lara_django_projects_pb2.ProjectCalendarListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving projectcalendar_name: {e}")
        if len(results) == 1 :
            return results[0].projectcalendar_id
        else:
            raise ValueError(f"Error retrieving projectcalendar_id - no or too many results found.")

    async def get_by_id(self, projectcalendar_id: str = None) -> projects_dm.ProjectCalendar:
        """ retrieve a projectcalendar data model by projectcalendar_id """
        try:
            res = await self.projectcalendar_client.Retrieve(
                lara_django_projects_pb2.ProjectCalendarRetrieveRequest(projectcalendar_id=projectcalendar_id)
            )
            return projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectcalendar_id: {e}")

    async def get_by_name(self, projectcalendar_name: str = None) -> projects_dm.ProjectCalendar:
        """ retrieve a projectcalendar data model by projectcalendar_name """
        try:
            res = await self.projectcalendar_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ProjectCalendarRetrieveByNameNSRequest(name=projectcalendar_name, namespace_uri="")
            )
            return projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectcalendar_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all projectcalendars """
        if filter_dict is None:
            res = await self.projectcalendar_client.List(lara_django_projects_pb2.ProjectCalendarListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectcalendar_client.List(
                lara_django_projects_pb2.ProjectCalendarListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectcalendar_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all projectcalendars """
        if self.projectcalendar_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectcalendar_full_client.List(
                lara_django_projects_pb2.ProjectCalendarFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectcalendar_full_client.List(
                lara_django_projects_pb2.ProjectCalendarFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, projectcalendar : projects_dm.ProjectCalendar = None) -> None:
        """ update a projectcalendar model instance """
        try:
            await self.projectcalendar_client.Update(
                lara_django_projects_pb2.ProjectCalendarRequest(**projectcalendar.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating projectcalendar_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a projectcalendar by projectcalendar_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.projectcalendar_client.Destroy(lara_django_projects_pb2.ProjectCalendarDestroyRequest(projectcalendar_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting projectcalendar_id: {e}")

#_________________  ExperimentCalendar  ______________________


class ExperimentCalendarInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.experimentcalendar_client = lara_django_projects_pb2_grpc.ExperimentCalendarControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  experimentcalendars:  list[projects_dm.ExperimentCalendar] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ExperimentCalendar]]:
        try:
            create_coroutines = ( self.experimentcalendar_client.Create(lara_django_projects_pb2.ExperimentCalendarRequest(**experimentcalendar.model_dump())) for experimentcalendar in experimentcalendars )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experimentcalendar_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating experimentcalendar: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        experimentcalendar_id: str = None,
        experimentcalendar_name: str = None,
        #experimentcalendar_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ExperimentCalendar]:
        """ retrieve a list of experimentcalendar instances by experimentcalendar_id, experimentcalendar_name or filter_dict,
               returns a list of experimentcalendar data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  experimentcalendar_id is not None:
            try:
                res =  await self.experimentcalendar_client.Retrieve(
                    lara_django_projects_pb2.ExperimentCalendarRetrieveRequest(experimentcalendar_id=experimentcalendar_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving experimentcalendar_id: {e}")

        if experimentcalendar_name is not None:
            filter_list.append({"name": experimentcalendar_name})
        # if experimentcalendar_name_display is not None:
        #     filter_list.append({"name_display": experimentcalendar_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentcalendar_client.List(
                        lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving experimentcalendar_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          experimentcalendar_name: str = None,
                          experimentcalendar_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the experimentcalendar_id for a given experimentcalendar_name,
               experimentcalendar_name_display or iri
        """
        if experimentcalendar_name is not None:
            filter_dict = {"name": experimentcalendar_name}
        elif experimentcalendar_name_display is not None:
            filter_dict = {"name_display": experimentcalendar_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.experimentcalendar_client.List(
                lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving experimentcalendar_name: {e}")
        if len(results) == 1 :
            return results[0].experimentcalendar_id
        else:
            raise ValueError(f"Error retrieving experimentcalendar_id - no or too many results found.")

    async def get_by_id(self, experimentcalendar_id: str = None) -> projects_dm.ExperimentCalendar:
        """ retrieve a experimentcalendar data model by experimentcalendar_id """
        try:
            res = await self.experimentcalendar_client.Retrieve(
                lara_django_projects_pb2.ExperimentCalendarRetrieveRequest(experimentcalendar_id=experimentcalendar_id)
            )
            return projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experimentcalendar_id: {e}")

    async def get_by_name(self, experimentcalendar_name: str = None) -> projects_dm.ExperimentCalendar:
        """ retrieve a experimentcalendar data model by experimentcalendar_name """
        try:
            res = await self.experimentcalendar_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ExperimentCalendarRetrieveByNameNSRequest(name=experimentcalendar_name, namespace_uri="")
            )
            return projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving experimentcalendar_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all experimentcalendars """
        if filter_dict is None:
            res = await self.experimentcalendar_client.List(lara_django_projects_pb2.ExperimentCalendarListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experimentcalendar_client.List(
                lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experimentcalendar_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all experimentcalendars """
        if self.experimentcalendar_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experimentcalendar_full_client.List(
                lara_django_projects_pb2.ExperimentCalendarFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experimentcalendar_full_client.List(
                lara_django_projects_pb2.ExperimentCalendarFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, experimentcalendar : projects_dm.ExperimentCalendar = None) -> None:
        """ update a experimentcalendar model instance """
        try:
            await self.experimentcalendar_client.Update(
                lara_django_projects_pb2.ExperimentCalendarRequest(**experimentcalendar.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating experimentcalendar_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a experimentcalendar by experimentcalendar_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.experimentcalendar_client.Destroy(lara_django_projects_pb2.ExperimentCalendarDestroyRequest(experimentcalendar_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting experimentcalendar_id: {e}")

#_________________  ProjectSynchronisation  ______________________


class ProjectSynchronisationInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self._default_namespace_uri = None
        self._default_namespace_id = None

        # if default_namespace_uri is not None:
        #     await self.set_default_namespace_uri(default_namespace_uri)

        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectsynchronisation_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectSynchronisationclassByIRIControllerStub(channel)
        # )

        self.projectsynchronisation_client = lara_django_projects_pb2_grpc.ProjectSynchronisationControllerStub(channel)

        self.update_item_id = "projectsynchronisation_id"
        self.stub = self.projectsynchronisation_client

        self.file_upload_chunk = lara_django_projects_pb2.FileUploadChunk


        # self.projectsynchronisation_full_client = lara_django_projects_pb2_grpc.ProjectSynchronisationFullControllerStub(
        #     channel
        # )

    @property
    def default_namespace_uri(self):
        return self._default_namespace_uri
    @property
    def default_namespace_id(self):
        return self._default_namespace_id

    async def set_default_namespace_uri(self, namespace_uri: str = None):
        if namespace_uri is not None:
            self._default_namespace_uri = namespace_uri.strip()
        try:
            self._default_namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logger.error(f"Error retrieving namespace_id: {e}")

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    @upload_file  # needed for file upload
    async def create(self,  projectsynchronisations:  list[projects_dm.ProjectSynchronisation] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ProjectSynchronisation]]:
        """ create a list of projectsynchronisation instances,
               returns a list of projectsynchronisation data model objects or ids_only

        :param projectsynchronisations: list of projectsynchronisation data model objects
        :param ids_only: return only the ids of the created instances
        :return: list of projectsynchronisation data model objects or ids_only
        """
        projectsynchronisationclass_id = None

        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectsynchronisation_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectsynchronisation_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectSynchronisationclassRetrieveRequest(iri=projectsynchronisation_class_iri)
        #     )
        #     projectsynchronisationclass_id = res.projectsynchronisationclass_id
        # except Exception as e:
        #     logger.error(f"Error retrieving projectsynchronisationclass_id: {e}")
        for projectsynchronisation in projectsynchronisations:
            if self._default_namespace_id is not None:
                if projectsynchronisation.namespace == "" or projectsynchronisation.namespace == "default":
                    projectsynchronisation.namespace = self._default_namespace_id
            # projectsynchronisation.projectsynchronisation_class = projectsynchronisationclass_id # uncomment if a model class is used

        try:
            create_coroutines = ( self.projectsynchronisation_client.Create(lara_django_projects_pb2.ProjectSynchronisationRequest(**projectsynchronisation.model_dump())) for projectsynchronisation in projectsynchronisations )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectsynchronisation_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating projectsynchronisation: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        namespace_uri: str = None,
        projectsynchronisation_id: str = None,
        projectsynchronisation_name: str = None,
        #projectsynchronisation_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectSynchronisation]:
        """ retrieve a list of projectsynchronisation instances by projectsynchronisation_id, projectsynchronisation_name or filter_dict,
               returns a list of projectsynchronisation data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None and projectsynchronisation_id is None:
            # TODO: define NoNamespaceURIError
            raise ValueError("No namespace URI is given.")
        filter_list = []
        results_list = []
        if  projectsynchronisation_id is not None:
            try:
                res =  await self.projectsynchronisation_client.Retrieve(
                    lara_django_projects_pb2.ProjectSynchronisationRetrieveRequest(projectsynchronisation_id=projectsynchronisation_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving projectsynchronisation_id: {e}")

        if projectsynchronisation_name is not None:
            filter_list.append({"name": projectsynchronisation_name})
        if namespace_uri is not None:
            filter_list.append({"namespace__uri": namespace_uri})
        # if projectsynchronisation_name_display is not None:
        #     filter_list.append({"name_display": projectsynchronisation_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsynchronisation_client.List(
                        lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving projectsynchronisation_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          projectsynchronisation_name: str = None,
                          projectsynchronisation_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the projectsynchronisation_id for a given projectsynchronisation_name,
               projectsynchronisation_name_display or iri
        """
        if projectsynchronisation_name is not None:
            filter_dict = {"name": projectsynchronisation_name}
        elif projectsynchronisation_name_display is not None:
            filter_dict = {"name_display": projectsynchronisation_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.projectsynchronisation_client.List(
                lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving projectsynchronisation_name: {e}")
        if len(results) == 1 :
            return results[0].projectsynchronisation_id
        else:
            raise ValueError(f"Error retrieving projectsynchronisation_id - no or too many results found.")

    @download_file  # needed for file download
    async def get_by_id(self, projectsynchronisation_id: str = None) -> projects_dm.ProjectSynchronisation:
        """ retrieve a projectsynchronisation data model by projectsynchronisation_id """
        try:
            res = await self.projectsynchronisation_client.Retrieve(
                lara_django_projects_pb2.ProjectSynchronisationRetrieveRequest(projectsynchronisation_id=projectsynchronisation_id)
            )
            return projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectsynchronisation_id: {e}")

    @download_file  # needed for file download
    async def get_by_name(self, projectsynchronisation_name: str = None,
                                namespace_uri : str = None) -> projects_dm.ProjectSynchronisation:
        """ retrieve a projectsynchronisation data model by projectsynchronisation_name """
        if namespace_uri is None and self._default_namespace_uri is not None:
            namespace_uri = self._default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            res = await self.projectsynchronisation_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ProjectSynchronisationRetrieveByNameNSRequest(name=projectsynchronisation_name, namespace_uri=namespace_uri)
            )
            return projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectsynchronisation_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all projectsynchronisations """
        if filter_dict is None:
            res = await self.projectsynchronisation_client.List(lara_django_projects_pb2.ProjectSynchronisationListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectsynchronisation_client.List(
                lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectsynchronisation_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all projectsynchronisations """
        if self.projectsynchronisation_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectsynchronisation_full_client.List(
                lara_django_projects_pb2.ProjectSynchronisationFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectsynchronisation_full_client.List(
                lara_django_projects_pb2.ProjectSynchronisationFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    @update_file  # needed for file update
    async def update(self, projectsynchronisation : projects_dm.ProjectSynchronisation = None) -> None:
        """ update a projectsynchronisation model instance """
        try:
            await self.projectsynchronisation_client.Update(
                lara_django_projects_pb2.ProjectSynchronisationRequest(**projectsynchronisation.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating projectsynchronisation_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a projectsynchronisation by projectsynchronisation_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.projectsynchronisation_client.Destroy(lara_django_projects_pb2.ProjectSynchronisationDestroyRequest(projectsynchronisation_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting projectsynchronisation_id: {e}")

#_________________  ProjectSyncStatus  ______________________


class ProjectSyncStatusInterface:
    def __init__(self, channel: grpc.Channel = None) -> None:
        if channel is None:
            cs = GRPCChannelSingleton()
            channel = cs.channel

        self.projectsyncstatus_client = lara_django_projects_pb2_grpc.ProjectSyncStatusControllerStub(channel)


    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def create(self,  projectsyncstatus:  list[projects_dm.ProjectSyncStatus] = None,  ids_only: bool = False) -> Union[list[str], list[projects_dm.ProjectSyncStatus]]:
        try:
            create_coroutines = ( self.projectsyncstatus_client.Create(lara_django_projects_pb2.ProjectSyncStatusRequest(**projectsyncstatus.model_dump())) for projectsyncstatus in projectsyncstatus )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectsyncstatus_id for item in res]
            else:
                return res

        except Exception as e:
            logger.error(f"Error creating projectsyncstatus: {e}")

    @export_model_instance_to_file
    async def retrieve(
        self,
        projectsyncstatus_id: str = None,
        projectsyncstatus_name: str = None,
        #projectsyncstatus_name_display: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectSyncStatus]:
        """ retrieve a list of projectsyncstatus instances by projectsyncstatus_id, projectsyncstatus_name or filter_dict,
               returns a list of projectsyncstatus data model objects,
               if raw is True, the raw protobuf objects are returned
        """
        filter_list = []
        results_list = []
        if  projectsyncstatus_id is not None:
            try:
                res =  await self.projectsyncstatus_client.Retrieve(
                    lara_django_projects_pb2.ProjectSyncStatusRetrieveRequest(projectsyncstatus_id=projectsyncstatus_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logger.error(f"Error retrieving projectsyncstatus_id: {e}")

        if projectsyncstatus_name is not None:
            filter_list.append({"name": projectsyncstatus_name})
        # if projectsyncstatus_name_display is not None:
        #     filter_list.append({"name_display": projectsyncstatus_name_display})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsyncstatus_client.List(
                        lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logger.error(f"Error retrieving projectsyncstatus_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self,
                          projectsyncstatus_name: str = None,
                          projectsyncstatus_name_display: str = None,
                          iri: str = None,) -> str:
        """ retrieve the projectsyncstatus_id for a given projectsyncstatus_name,
               projectsyncstatus_name_display or iri
        """
        if projectsyncstatus_name is not None:
            filter_dict = {"name": projectsyncstatus_name}
        elif projectsyncstatus_name_display is not None:
            filter_dict = {"name_display": projectsyncstatus_name_display}
        elif iri is not None:
            filter_dict = {"iri": iri}
        metadata = (("filters", (json.dumps(filter_dict))),)
        try:
            res = await self.projectsyncstatus_client.List(
                lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
            )
            results = res.results
        except Exception as e:
            logger.error(f"Error retrieving projectsyncstatus_name: {e}")
        if len(results) == 1 :
            return results[0].projectsyncstatus_id
        else:
            raise ValueError(f"Error retrieving projectsyncstatus_id - no or too many results found.")

    async def get_by_id(self, projectsyncstatus_id: str = None) -> projects_dm.ProjectSyncStatus:
        """ retrieve a projectsyncstatus data model by projectsyncstatus_id """
        try:
            res = await self.projectsyncstatus_client.Retrieve(
                lara_django_projects_pb2.ProjectSyncStatusRetrieveRequest(projectsyncstatus_id=projectsyncstatus_id)
            )
            return projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectsyncstatus_id: {e}")

    async def get_by_name(self, projectsyncstatus_name: str = None) -> projects_dm.ProjectSyncStatus:
        """ retrieve a projectsyncstatus data model by projectsyncstatus_name """
        try:
            res = await self.projectsyncstatus_client.RetrieveByNameNamespace(
                lara_django_projects_pb2.ProjectSyncStatusRetrieveByNameNSRequest(name=projectsyncstatus_name, namespace_uri="")
            )
            return projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True))
        except Exception as e:
            logger.error(f"Error retrieving projectsyncstatus_name: {e}")

    async def list_items(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        """ list all projectsyncstatuss """
        if filter_dict is None:
            res = await self.projectsyncstatus_client.List(lara_django_projects_pb2.ProjectSyncStatusListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectsyncstatus_client.List(
                lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectsyncstatus_id for item in res.results]
        else:
            return res.results

    async def list_full(self, filter_dict: dict = None) -> list:
        """ list all projectsyncstatuss """
        if self.projectsyncstatus_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectsyncstatus_full_client.List(
                lara_django_projects_pb2.ProjectSyncStatusFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectsyncstatus_full_client.List(
                lara_django_projects_pb2.ProjectSyncStatusFullListRequest(), metadata=metadata
            )

    @import_model_instance_from_file(relation_resolver=lambda x: x)
    async def update(self, projectsyncstatus : projects_dm.ProjectSyncStatus = None) -> None:
        """ update a projectsyncstatus model instance """
        try:
            await self.projectsyncstatus_client.Update(
                lara_django_projects_pb2.ProjectSyncStatusRequest(**projectsyncstatus.model_dump()
            ))
        except Exception as e:
            logger.error(f"Error updating projectsyncstatus_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        """ delete a projectsyncstatus by projectsyncstatus_id or filter_dict """
        if filter_dict is not None:
            id_list = await self.list_items(filter_dict=filter_dict, ids_only=True)

        try:
            delete_coroutines = ( self.projectsyncstatus_client.Destroy(lara_django_projects_pb2.ProjectSyncStatusDestroyRequest(projectsyncstatus_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)

        except Exception as e:
            logger.error(f"Error deleting projectsyncstatus_id: {e}")
