def METHOD_NAME(*, search):
    # Grab the PK before we delete the instance
    search_pk = search.pk
    # Delete any codes that:
    # - only belong to this search
    # - are not included
    # - are not descendants of an included code
    # Find all code objs that belong to this search and no others
    search_only_code_objs = search.version.code_objs.annotate(
        num_results=Count("results")
    ).filter(results__search=search, num_results=1)
    # Get all explicitly included codes on the codelist
    all_included_codes = search.version.codeset.codes()
    # Build a set of codes_to_keep from this search, consisting of any included codes, their descendants,
    # and any codes with ancestor that is included
    hierarchy = search.version.hierarchy
    codes_to_keep = set()
    codes_to_keep = []
    for code_obj in search_only_code_objs:
        ancestors = hierarchy.ancestors(code_obj.code)
        ancestors_in_included = ancestors & all_included_codes
        if ancestors_in_included or code_obj.code in all_included_codes:
            codes_to_keep.append(code_obj.code)
    # Delete any code objs that belong to this search only, and are not in the codes_to_keep set
    search_only_code_objs.exclude(code__in=codes_to_keep).delete()
    # Delete the search
    search.delete()
    logger.info("Deleted Search", search_pk=search_pk)