def filter(
        cls: Type[TYetiObject],
        query_args: dict[str, Any],
        offset: int = 0,
        count: int = 0,
        sorting: List[tuple[str, bool]] = [],
        aliases: List[tuple[str, str]] = [],
        graph_queries: List[tuple[str, str, str, str]] = [],
        links_count: bool = False,
        wildcard: bool = True,
        user: "user.User" = None,
    ) -> tuple[List[TYetiObject], int]:
        """Search in an ArangoDb collection.

        Search the collection for all objects whose 'value' attribute matches
        the regex defined in the 'value' key of the args dict.

        Args:
            query_args: A key:value dictionary containing keys to filter objects
                on.
            offset: Skip this many objects when querying the DB.
            count: How many objecst after `offset` to return.
            sorting: A list of (order, ascending) fields to sort by.
            graph_queries: A list of (name, graph, direction, field) tuples to
                query the graph with.
            wildcard: whether all values should be interpreted as wildcard searches.
            user: A user to perform the query for.

        Returns:
            A List of Yeti objects, and the total object count.
        """
        cls._get_collection()
        colname = cls._collection_name
        conditions = []
        filter_conditions = []  # used for clauses that are not supported by arangosearch
        sorts = []

        using_view = False
        if (
            query_args
            and colname in ("observables", "entities", "indicators", "dfiq")
            and wildcard
            # and not any([key.endswith("~") for key in query_args])
        ):
            using_view = True
            colname += "_view"

        # We want user-defined sorts to take precedence.
        links_count_query = ""
        if links_count:
            links_count_query = """
            LET aggregated_links = MERGE(
                FOR v, e IN 1..1 ANY o links COLLECT root_type = v.root_type INTO vtypes = {'type': v.type}
                LET sub_types = MERGE(FOR vt IN vtypes COLLECT vtype = vt.type WITH COUNT INTO type_count RETURN {[vtype]: type_count})
                LET details = MERGE(sub_types, {'total': SUM(VALUES(sub_types))})
                RETURN {[root_type]: details}
            )
            LET total_links = SUM(FOR k IN ATTRIBUTES(aggregated_links) RETURN aggregated_links[k].total)
            """

        for field, asc in sorting:
            if field == "total_links" and links_count:
                sorts.append(f"total_links {'ASC' if asc else 'DESC'}")
            else:
                sorts.append(f"o.{field} {'ASC' if asc else 'DESC'}")

        aql_args: dict[str, str | int | list] = {}
        for i, (key, value) in enumerate(list(query_args.items())):
            if key.endswith("~"):
                using_regex = True
                key = key[:-1]
            else:
                using_regex = False
            if isinstance(value, str):
                aql_args[f"arg{i}_value"] = value
            elif isinstance(value, list):
                aql_args[f"arg{i}_value"] = [v.strip() for v in value]

            if key.startswith("in__"):
                if using_view:
                    conditions.append(f"o.@arg{i}_key IN @arg{i}_value")
                else:
                    conditions.append(f"o.@arg{i}_key IN [@arg{i}_value]")
                aql_args[f"arg{i}_key"] = key[4:]
            elif key.endswith("__in"):  # o.value is in [1, 2, 3]
                conditions.append(f"o.@arg{i}_key IN @arg{i}_value")
                aql_args[f"arg{i}_key"] = key[:-4]
            elif key in {"labels", "relevant_tags"}:
                conditions.append(f"o.@arg{i}_key IN @arg{i}_value")
                aql_args[f"arg{i}_key"] = key
            elif key == "tags":
                if using_view:
                    conditions.append(f"@arg{i}_value ALL IN o.tags.name")
                else:
                    conditions.append(f"@arg{i}_value ALL IN o.tags[*].name")
            elif key in ("created", "modified", "tags.expires"):
                # Value is a string, we're checking the first character.
                operator = value[0]
                if operator not in ["<", ">"]:
                    operator = "="
                else:
                    aql_args[f"arg{i}_value"] = value[1:]
                if key == "tags.expires":
                    filter_conditions.append(
                        f"o.tags[* RETURN DATE_TIMESTAMP(CURRENT.expires)] ANY {operator} DATE_TIMESTAMP(@arg{i}_value)"
                    )
                else:
                    filter_conditions.append(
                        f"DATE_TIMESTAMP(o.{key}) {operator}= DATE_TIMESTAMP(@arg{i}_value)"
                    )
                    sorts.append(f"o.{key}")
            elif key in ("name", "value"):
                if using_view and not using_regex:
                    aql_args[f"arg{i}_value"] = f"%{value}%"
                    key_conditions = [
                        f"ANALYZER(LIKE(o.@arg{i}_key, LOWER(@arg{i}_value)), 'norm')"
                    ]
                else:
                    key_conditions = [f"REGEX_TEST(o.@arg{i}_key, @arg{i}_value, true)"]

                for alias, alias_type in aliases:
                    if (
                        alias_type in {"text", "option"}
                        or alias_type == "list"
                        and using_view
                    ):
                        if using_view and not using_regex:
                            key_conditions.append(
                                f"ANALYZER(LIKE(o.{alias}, LOWER(@arg{i}_value)), 'norm')"
                            )
                        else:
                            key_conditions.append(
                                f"REGEX_TEST(o.{alias}, @arg{i}_value, true)"
                            )
                    elif alias_type == "list":
                        if using_regex:
                            key_conditions.append(
                                f"COUNT(FOR i IN o.{alias} || [] FILTER REGEX_TEST(i, @arg{i}_value, true) RETURN i) > 0"
                            )
                        else:
                            key_conditions.append(
                                f"COUNT(FOR i IN o.{alias} || [] FILTER LIKE(i, @arg{i}_value) RETURN i) > 0"
                            )
                key_condition = " OR ".join(key_conditions)
                if using_regex:
                    filter_conditions.append(f"({key_condition})")
                else:
                    conditions.append(f"({key_condition})")
                aql_args[f"arg{i}_key"] = key
            else:
                aql_args[f"arg{i}_key"] = key
                if using_regex:
                    filter_conditions.append(
                        f"REGEX_TEST(o.@arg{i}_key, @arg{i}_value, true)"
                    )
                else:
                    aql_args[f"arg{i}_value"] = f"%{value}%"
                    conditions.append(f"LIKE(o.@arg{i}_key, @arg{i}_value)")

        limit = ""
        if count != 0:
            limit = "LIMIT @offset, @count"
            aql_args["offset"] = offset
            aql_args["count"] = count

        # TODO: Interpolate this query
        graph_query_string = ""
        for name, graph, direction, field in graph_queries:
            field_aggregation = "||".join([f"v.{field}" for field in field.split("|")])
            graph_query_string += f"\nLET {name} = (FOR v, e in 1..1 {direction} o {graph} RETURN {{ [{field_aggregation}]: e }})"

        acl_query = ""
        if user and RBAC_ENABLED and not user.admin:
            acl_query = "LET acl = FIRST(FOR v, e, p in 1..2 inbound o acls FILTER v.username == @username RETURN true) or false"
            aql_args["username"] = user.username

        filter_string = ""
        if filter_conditions:
            filter_string = f"FILTER {' AND '.join(filter_conditions)}"

        aql_search = ""
        if conditions:
            aql_search = (
                f"{'SEARCH' if using_view else 'FILTER'} {' AND '.join(conditions)}"
            )

        aql_sort = ""
        if sorts:
            aql_sort = f"SORT {', '.join(sorts)}"

        acl_filter = ""
        if acl_query:
            acl_filter = "FILTER acl"

        aql_string = f"""
            FOR o IN @@collection
                {aql_search}
                {links_count_query}
                {graph_query_string}
                {acl_query}
                {filter_string}
                {acl_filter}
                {aql_sort}
                {limit}
            """
        merged_list = ""
        with_statements = []
        if graph_queries:
            merged_list = ", ".join(
                [f"{name}: MERGE({name})" for name, _, _, _ in graph_queries]
            )
            with_statements.extend([name for name, _, _, _ in graph_queries])
        if acl_query:
            with_statements.append("acls")
        if links_count:
            merged_list += (
                ", aggregated_links, total_links"
                if merged_list
                else "aggregated_links, total_links"
            )

        prologue = ""
        if with_statements:
            prologue = f"WITH {', '.join(with_statements)}"
        if merged_list:
            aql_string = (
                f"{prologue}\n\n{aql_string}\nRETURN MERGE(o, {{ {merged_list} }})\n"
            )
        else:
            aql_string += "\nRETURN o"
        aql_args["@collection"] = colname
        logging.debug(f"aql_string: {aql_string}, aql_args: {aql_args}")
        documents = cls._db.aql.execute(
            aql_string, bind_vars=aql_args, count=True, full_count=True
        )
        stats = documents.statistics()
        results = []
        for doc in documents:
            doc["__id"] = doc.pop("_key")
            results.append(cls.load(doc))
        total = stats.get("fullCount", len(results))
        return results, total or 0
Search in an ArangoDb collection.

        Search the collection for all objects whose 'value' attribute matches
        the regex defined in the 'value' key of the args dict.

        Args:
            query_args: A key:value dictionary containing keys to filter objects
                on.
            offset: Skip this many objects when querying the DB.
            count: How many objecst after `offset` to return.
            sorting: A list of (order, ascending) fields to sort by.
            graph_queries: A list of (name, graph, direction, field) tuples to
                query the graph with.
            wildcard: whether all values should be interpreted as wildcard searches.
            user: A user to perform the query for.

        Returns:
            A List of Yeti objects, and the total object count.
        
core/database_arango.py