Skip to content

Commit

Permalink
Handle In(key, []) and NotIn(key, []) correctly.
Browse files Browse the repository at this point in the history
  • Loading branch information
danielballan committed May 21, 2024
1 parent cc20d4a commit 61f50b1
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 14 deletions.
2 changes: 1 addition & 1 deletion tiled/_tests/test_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def test_notin(client, query_values):


def test_not_in_empty(client):
assert list(client.search(NotIn("letter", []))) == []
assert sorted(list(client.search(NotIn("letter", [])))) == sorted(list(client))


@pytest.mark.parametrize(
Expand Down
2 changes: 2 additions & 0 deletions tiled/adapters/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,8 @@ def notin(query: Any, tree: MapAdapter) -> MapAdapter:
"""
matches = {}
if len(query.value) == 0:
return tree
for key, value, term in iter_child_metadata(query.key, tree):
if term not in query.value:
matches[key] = value
Expand Down
55 changes: 42 additions & 13 deletions tiled/catalog/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,19 @@

import anyio
from fastapi import HTTPException
from sqlalchemy import delete, event, func, not_, or_, select, text, type_coerce, update
from sqlalchemy import (
delete,
event,
false,
func,
not_,
or_,
select,
text,
true,
type_coerce,
update,
)
from sqlalchemy.dialects.postgresql import JSONB, REGCONFIG
from sqlalchemy.engine import make_url
from sqlalchemy.exc import IntegrityError
Expand Down Expand Up @@ -1207,31 +1219,48 @@ def specs(query, tree):
return tree.new_variation(conditions=tree.conditions + conditions)


def in_or_not_in_sqlite(query, tree, method, keys, attr):
def in_or_not_in_sqlite(query, tree, method):
keys = query.key.split(".")
attr = orm.Node.metadata_[keys]
condition = getattr(_get_value(attr, type(query.value[0])), method)(query.value)
if len(query.value) == 0:
if method == "in_":
# Results cannot possibly be "in" in an empty list,
# so put a False condition in the list ensuring that
# there are no rows return.
condition = false()
else: # method == "not_in"
# All results are always "not in" an empty list.
condition = true()
else:
condition = getattr(_get_value(attr, type(query.value[0])), method)(query.value)
return tree.new_variation(conditions=tree.conditions + [condition])


def in_or_not_in_postgresql(query, tree, method):
keys = query.key.split(".")
# Engage btree_gin index with @> operator
if method == "in_":
condition = or_(
*(
orm.Node.metadata_.op("@>")(key_array_to_json(keys, item))
for item in query.value
)
)
elif method == "not_in":
condition = not_(
or_(
if len(query.value) == 0:
condition = false()
else:
condition = or_(
*(
orm.Node.metadata_.op("@>")(key_array_to_json(keys, item))
for item in query.value
)
)
)
elif method == "not_in":
if len(query.value) == 0:
condition = true()
else:
condition = not_(
or_(
*(
orm.Node.metadata_.op("@>")(key_array_to_json(keys, item))
for item in query.value
)
)
)
return tree.new_variation(conditions=tree.conditions + [condition])


Expand Down

0 comments on commit 61f50b1

Please sign in to comment.