Return an Expression that is False for rows that don't follow the @optional specification.

    OrientDB does not filter correctly within optionals. Namely, a result where the optional edge
    DOES EXIST will be returned regardless of whether the inner filter is satisfed.
    To mitigate this, we add a final filter to reject such results.
    A valid result must satisfy either of the following:
    - The location within the optional exists (the filter will have been applied in this case)
    - The optional edge field does not exist at the root location of the optional traverse
    So, if the inner location within the optional was never visited, it must be the case that
    the corresponding edge field does not exist at all.

    Example:
        A MATCH traversal which starts at location `Animal___1`, and follows the optional edge
        `out_Animal_ParentOf` to the location `Animal__out_Animal_ParentOf___1`
        results in the following filtering Expression:
        (
            (
                (Animal___1.out_Animal_ParentOf IS null)
                OR
                (Animal___1.out_Animal_ParentOf.size() = 0)
            )
            OR
            (Animal__out_Animal_ParentOf___1 IS NOT null)
        )
        Here, the `optional_edge_location` is `Animal___1.out_Animal_ParentOf`.

    Args:
        query_metadata_table: QueryMetadataTable object containing all metadata collected during
                              query processing, including location metadata (e.g. which locations
                              are folded or optional).
        optional_edge_location: Location object representing the optional edge field
        inner_location_name: string representing location within the corresponding optional traverse

    Returns:
        Expression that evaluates to False for rows that do not follow the @optional specification

def _filter_orientdb_simple_optional_edge(
        query_metadata_table, optional_edge_location, inner_location_name):
    """Return an Expression that is False for rows that don't follow the @optional specification.

    OrientDB does not filter correctly within optionals. Namely, a result where the optional edge
    DOES EXIST will be returned regardless of whether the inner filter is satisfed.
    To mitigate this, we add a final filter to reject such results.
    A valid result must satisfy either of the following:
    - The location within the optional exists (the filter will have been applied in this case)
    - The optional edge field does not exist at the root location of the optional traverse
    So, if the inner location within the optional was never visited, it must be the case that
    the corresponding edge field does not exist at all.

    Example:
        A MATCH traversal which starts at location `Animal___1`, and follows the optional edge
        `out_Animal_ParentOf` to the location `Animal__out_Animal_ParentOf___1`
        results in the following filtering Expression:
        (
            (
                (Animal___1.out_Animal_ParentOf IS null)
                OR
                (Animal___1.out_Animal_ParentOf.size() = 0)
            )
            OR
            (Animal__out_Animal_ParentOf___1 IS NOT null)
        )
        Here, the `optional_edge_location` is `Animal___1.out_Animal_ParentOf`.

    Args:
        query_metadata_table: QueryMetadataTable object containing all metadata collected during
                              query processing, including location metadata (e.g. which locations
                              are folded or optional).
        optional_edge_location: Location object representing the optional edge field
        inner_location_name: string representing location within the corresponding optional traverse

    Returns:
        Expression that evaluates to False for rows that do not follow the @optional specification
    """
    inner_local_field = LocalField(inner_location_name)
    inner_location_existence = BinaryComposition(u'!=', inner_local_field, NullLiteral)

    # The optional_edge_location here is actually referring to the edge field itself.
    # This is definitely non-standard, but required to get the proper semantics.
    # To get its type, we construct the location of the vertex field on the other side of the edge.
    vertex_location = (
        optional_edge_location.at_vertex().navigate_to_subpath(optional_edge_location.field)
    )
    location_type = query_metadata_table.get_location_info(vertex_location).type

    edge_context_field = GlobalContextField(optional_edge_location, location_type)
    edge_field_non_existence = filter_edge_field_non_existence(edge_context_field)

    return BinaryComposition(u'||', edge_field_non_existence, inner_location_existence)