Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion fairgraph/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Equals(str):
The KG ignores case when matching, but not whitespace, so `Equals("FOO")` does match "foo",
but not "FOO ".

Only a single value is supported: a list of `Equals` values is filtered with "CONTAINS".
Only a single value is supported: filtering on a list of values raises a TypeError.

Args:
value (str): the value the property must be equal to.
Expand Down Expand Up @@ -495,6 +495,15 @@ def get_query_filter_property(property, context, filter: Any) -> QueryProperty:
filter_obj = None
else:
# we have a filter value for this property
if isinstance(filter, list):
# The KG query API only supports a single value per filter, so there is no
# way to express "any of these values". Reject the list rather than silently
# changing the meaning of the query (e.g. by sending CONTAINS with a list).
raise TypeError(
"Filtering on a list of values is not supported: "
"the KG query API applies a single value per filter. "
"Filter on one value at a time instead."
)
if isinstance(filter, Regex):
op = "REGEX"
elif isinstance(filter, Equals):
Expand Down
28 changes: 28 additions & 0 deletions test/test_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,34 @@ def test_equals_rejects_a_non_id_string_for_a_link(mock_client):
omcore.DatasetVersion.generate_query(client=mock_client, space=None, filters={"is_new_version_of": Equals("FOO")})


@pytest.mark.parametrize(
"value",
[
[Equals("FOO"), Equals("BAR")],
[Regex("^FOO$"), Regex("^BAR$")],
["FOO", "BAR"],
],
)
def test_list_filter_values_are_rejected(mock_client, value):
# the KG query API only supports a single value per filter, so a list must not
# be silently turned into a CONTAINS filter whose value is the whole list
with pytest.raises(TypeError):
omcore.Dataset.generate_query(client=mock_client, space=None, filters={"short_name": value})


def test_list_filter_values_are_rejected_for_a_link(mock_client):
# a list value for a link-typed property used to crash with an AttributeError
# from str.startswith being called on the list
instance_ids = [
"https://kg.ebrains.eu/api/instances/00000000-0000-0000-0000-000000000001",
"https://kg.ebrains.eu/api/instances/00000000-0000-0000-0000-000000000002",
]
with pytest.raises(TypeError):
omcore.DatasetVersion.generate_query(
client=mock_client, space=None, filters={"is_new_version_of": instance_ids}
)


def test_existence_query_filters_strings_with_equals(mock_client):
dataset = omcore.Dataset(short_name="FOO")
query = omcore.Dataset.generate_minimal_query(client=mock_client, filters=dataset._build_existence_query())
Expand Down