def get_resource_component_and_children(
        self, resource_id, resource_type="collection", level=1, sort_data={}, **kwargs
    ):
        """
        Fetch detailed metadata for the specified resource_id and all of its children.

        :param long resource_id: The resource for which to fetch metadata.
        :param string resource_type: The level of description of the record.
        :param int recurse_max_level: The maximum depth level to fetch when fetching children.
            Default is to fetch all of the resource's children, descending as deeply as necessary.
            Pass 1 to fetch no children.
        :param string search_pattern: If specified, limits fetched children to those whose titles or IDs match the provided query.
            See ArchivistsToolkitClient.find_collection_ids for documentation of the query format.

        :return: A dict containing detailed metadata about both the requested resource and its children.
            The dict follows this format:
        {
          'id': '31',
          'type': 'resource',
          'sortPosition': '1',
          'identifier': 'PR01',
          'title': 'Parent',
          'levelOfDescription': 'collection',
          'dates': '1880-1889',
          'date_expression': '1880 to 1889',
          'notes': [
            'type': 'odd',
            'content': 'This is a note',
          ],
          'children': [{
            'id': '23',
            'type': 'resource_component',
            'sortPosition': '2',
            'identifier': 'CH01',
            'title': 'Child A',
            'levelOfDescription': 'Sousfonds',
            'dates': '1880-1888',
            'date_expression': '1880 to 1888',
            'notes': [],
            'children': [{
              'id': '24',
              'type': 'resource_component',
              'sortPosition': '3',
              'identifier': 'GR01',
              'title': 'Grandchild A',
              'levelOfDescription': 'Item',
              'dates': '1880-1888',
              'date_expression': '1880 to 1888',
              'notes': [],
              'children': False
            },
            {
              'id': '25',
              'type': 'resource_component',
              'sortPosition': '4',
              'identifier': 'GR02',
              'title': 'Grandchild B',
              'levelOfDescription': 'Item',
              'notes': [],
              'children': False
            }]
          },
          {
            'id': '26',
            'type': 'resource_component',
            'sortPosition': '5',
            'identifier': 'CH02',
            'title': 'Child B',
            'levelOfDescription': 'Sousfonds',
            'dates': '1889',
            'date_expression': '1889',
            'notes': [],
            'children': False
          }]
        }
        :rtype list:
        """
        # we pass the sort position as a dict so it passes by reference and we
        # can use it to share state during recursion

        recurse_max_level = kwargs.get("recurse_max_level", False)
        query = kwargs.get("search_pattern", "")

        # intialize sort position if this is the beginning of recursion
        if level == 1:
            sort_data["position"] = 0

        sort_data["position"] = sort_data["position"] + 1

        resource_data = {}

        cursor = self.db.cursor()

        if resource_type == "collection":
            cursor.execute(
                "SELECT title, dateExpression, resourceIdentifier1, resourceLevel FROM Resources WHERE resourceid=%s",
                (resource_id),
            )

            for row in cursor.fetchall():
                resource_data["id"] = resource_id
                resource_data["type"] = "resource"
                resource_data["sortPosition"] = sort_data["position"]
                resource_data["title"] = row[0]
                # TODO reformat dates from the separate date fields, like ArchivesSpaceClient?
                resource_data["dates"] = row[1]
                resource_data["date_expression"] = row[1]
                resource_data["identifier"] = row[2]
                resource_data["levelOfDescription"] = row[3]
        else:
            cursor.execute(
                "SELECT title, dateExpression, persistentID, resourceLevel FROM ResourcesComponents WHERE resourceComponentId=%s",
                (resource_id),
            )

            for row in cursor.fetchall():
                resource_data["id"] = resource_id
                resource_data["type"] = "resource_component"
                resource_data["sortPosition"] = sort_data["position"]
                resource_data["title"] = row[0]
                resource_data["dates"] = row[1]
                resource_data["date_expression"] = row[1]
                resource_data["identifier"] = row[2]
                resource_data["levelOfDescription"] = row[3]

        # fetch children if we haven't reached the maximum recursion level
        if resource_type == "collection":
            if query == "":
                cursor.execute(
                    "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId IS NULL AND resourceId=%s ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC",
                    (resource_id),
                )
            else:
                cursor.execute(
                    "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId IS NULL AND resourceId=%s AND (title LIKE %s OR persistentID LIKE %s) ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC",
                    (resource_id, "%" + query + "%", "%" + query + "%"),
                )
        else:
            if query == "":
                cursor.execute(
                    "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId=%s ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC",
                    (resource_id),
                )
            else:
                cursor.execute(
                    "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId=%s AND (title LIKE %s OR persistentID LIKE %s) ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC",
                    (resource_id, "%" + query + "%", "%" + query + "%"),
                )

        rows = cursor.fetchall()

        if (not recurse_max_level) or level < recurse_max_level:
            if len(rows):
                resource_data["children"] = []
                resource_data["has_children"] = True

                for row in rows:
                    resource_data["children"].append(
                        self.get_resource_component_and_children(
                            row[0], "description", level + 1, sort_data
                        )
                    )
        else:
            if len(rows):
                resource_data["children"] = []
                resource_data["has_children"] = True
            else:
                resource_data["children"] = False
                resource_data["has_children"] = False

        # TODO: implement fetching notes
        resource_data["notes"] = []

        return resource_data
def get_resource_component_and_children ( self , resource_id , resource_type = "collection" , level = 1 , sort_data = { } , ** kwargs ) : recurse_max_level = kwargs . get ( "recurse_max_level" , False ) query = kwargs . get ( "search_pattern" , "" ) if level == 1 : sort_data [ "position" ] = 0 sort_data [ "position" ] = sort_data [ "position" ] + 1 resource_data = { } cursor = self . db . cursor ( ) if resource_type == "collection" : cursor . execute ( "SELECT title, dateExpression, resourceIdentifier1, resourceLevel FROM Resources WHERE resourceid=%s" , ( resource_id ) , ) for row in cursor . fetchall ( ) : resource_data [ "id" ] = resource_id resource_data [ "type" ] = "resource" resource_data [ "sortPosition" ] = sort_data [ "position" ] resource_data [ "title" ] = row [ 0 ] resource_data [ "dates" ] = row [ 1 ] resource_data [ "date_expression" ] = row [ 1 ] resource_data [ "identifier" ] = row [ 2 ] resource_data [ "levelOfDescription" ] = row [ 3 ] else : cursor . execute ( "SELECT title, dateExpression, persistentID, resourceLevel FROM ResourcesComponents WHERE resourceComponentId=%s" , ( resource_id ) , ) for row in cursor . fetchall ( ) : resource_data [ "id" ] = resource_id resource_data [ "type" ] = "resource_component" resource_data [ "sortPosition" ] = sort_data [ "position" ] resource_data [ "title" ] = row [ 0 ] resource_data [ "dates" ] = row [ 1 ] resource_data [ "date_expression" ] = row [ 1 ] resource_data [ "identifier" ] = row [ 2 ] resource_data [ "levelOfDescription" ] = row [ 3 ] if resource_type == "collection" : if query == "" : cursor . execute ( "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId IS NULL AND resourceId=%s ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC" , ( resource_id ) , ) else : cursor . execute ( "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId IS NULL AND resourceId=%s AND (title LIKE %s OR persistentID LIKE %s) ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC" , ( resource_id , "%" + query + "%" , "%" + query + "%" ) , ) else : if query == "" : cursor . execute ( "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId=%s ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC" , ( resource_id ) , ) else : cursor . execute ( "SELECT resourceComponentId FROM ResourcesComponents WHERE parentResourceComponentId=%s AND (title LIKE %s OR persistentID LIKE %s) ORDER BY FIND_IN_SET(resourceLevel, 'subseries,file'), title ASC" , ( resource_id , "%" + query + "%" , "%" + query + "%" ) , ) rows = cursor . fetchall ( ) if ( not recurse_max_level ) or level < recurse_max_level : if len ( rows ) : resource_data [ "children" ] = [ ] resource_data [ "has_children" ] = True for row in rows : resource_data [ "children" ] . append ( self . get_resource_component_and_children ( row [ 0 ] , "description" , level + 1 , sort_data ) ) else : if len ( rows ) : resource_data [ "children" ] = [ ] resource_data [ "has_children" ] = True else : resource_data [ "children" ] = False resource_data [ "has_children" ] = False resource_data [ "notes" ] = [ ] return resource_data
Fetch detailed metadata for the specified resource_id and all of its children.

        :param long resource_id: The resource for which to fetch metadata.
        :param string resource_type: The level of description of the record.
        :param int recurse_max_level: The maximum depth level to fetch when fetching children.
            Default is to fetch all of the resource's children, descending as deeply as necessary.
            Pass 1 to fetch no children.
        :param string search_pattern: If specified, limits fetched children to those whose titles or IDs match the provided query.
            See ArchivistsToolkitClient.find_collection_ids for documentation of the query format.

        :return: A dict containing detailed metadata about both the requested resource and its children.
            The dict follows this format:
        {
          'id': '31',
          'type': 'resource',
          'sortPosition': '1',
          'identifier': 'PR01',
          'title': 'Parent',
          'levelOfDescription': 'collection',
          'dates': '1880-1889',
          'date_expression': '1880 to 1889',
          'notes': [
            'type': 'odd',
            'content': 'This is a note',
          ],
          'children': [{
            'id': '23',
            'type': 'resource_component',
            'sortPosition': '2',
            'identifier': 'CH01',
            'title': 'Child A',
            'levelOfDescription': 'Sousfonds',
            'dates': '1880-1888',
            'date_expression': '1880 to 1888',
            'notes': [],
            'children': [{
              'id': '24',
              'type': 'resource_component',
              'sortPosition': '3',
              'identifier': 'GR01',
              'title': 'Grandchild A',
              'levelOfDescription': 'Item',
              'dates': '1880-1888',
              'date_expression': '1880 to 1888',
              'notes': [],
              'children': False
            },
            {
              'id': '25',
              'type': 'resource_component',
              'sortPosition': '4',
              'identifier': 'GR02',
              'title': 'Grandchild B',
              'levelOfDescription': 'Item',
              'notes': [],
              'children': False
            }]
          },
          {
            'id': '26',
            'type': 'resource_component',
            'sortPosition': '5',
            'identifier': 'CH02',
            'title': 'Child B',
            'levelOfDescription': 'Sousfonds',
            'dates': '1889',
            'date_expression': '1889',
            'notes': [],
            'children': False
          }]
        }
        :rtype list: