Skip to content

Commit

Permalink
feat: JSONB has_all
Browse files Browse the repository at this point in the history
  • Loading branch information
Chart.js committed Oct 4, 2022
1 parent c80bea6 commit 2f48df4
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ The maps to the [`contains`](https://docs.sqlalchemy.org/en/14/dialects/postgres
await JSONBTestModel.objects.filter(data__jsonb_contains=dict(key="value")).all()
```

##### jsonb_has_all

The maps to the [`has_all`](https://docs.sqlalchemy.org/en/14/dialects/postgresql.html#sqlalchemy.dialects.postgresql.JSONB.Comparator.has_all) operator in Postgres.

```python
from sqlalchemy.dialects.postgres import array

await JSONBTestModel.objects.filter(data__jsonb_has_all=array(["key1", "key2"])).all()
```

##### jsonb_has_any
##### jsonb_has_key

The maps to the [`has_key`](https://docs.sqlalchemy.org/en/14/dialects/postgresql.html#sqlalchemy.dialects.postgresql.JSONB.Comparator.has_key) operator in Postgres.
Expand Down
13 changes: 13 additions & 0 deletions src/ormar_postgres_extensions/fields/jsonb.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ def jsonb_contains(self, other: Any) -> ormar.queryset.clause.FilterGroup:
return self._select_operator(op="jsonb_contains", other=other)


def jsonb_has_all(self, other: Any) -> ormar.queryset.clause.FilterGroup:
"""
works as postgresql `column ?& VALUE::jsonb`
:param other: value to check against operator
:type other: Any
:return: FilterGroup for operator
:rtype: ormar.queryset.clause.FilterGroup
"""
return self._select_operator(op="jsonb_has_all", other=other)


def jsonb_has_key(self, other: Any) -> ormar.queryset.clause.FilterGroup:
"""
works as postgresql `column ? VALUE::jsonb`
Expand All @@ -41,6 +52,7 @@ def jsonb_has_key(self, other: Any) -> ormar.queryset.clause.FilterGroup:
FIELD_ACCESSOR_MAP = [
("jsonb_contained_by", jsonb_contained_by),
("jsonb_contains", jsonb_contains),
("jsonb_has_all", jsonb_has_all),
("jsonb_has_key", jsonb_has_key),
]

Expand All @@ -54,6 +66,7 @@ def jsonb_has_key(self, other: Any) -> ormar.queryset.clause.FilterGroup:
ACCESSOR_MAP = [
("jsonb_contained_by", "contained_by"),
("jsonb_contains", "contains"),
("jsonb_has_all", "has_all"),
("jsonb_has_key", "has_key"),
]

Expand Down
22 changes: 22 additions & 0 deletions tests/fields/test_jsonb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import ormar
import pytest
from sqlalchemy.dialects.postgresql import array

import ormar_postgres_extensions as ormar_pg_ext
from tests.database import (
Expand Down Expand Up @@ -123,6 +124,27 @@ async def test_contained_by(db):
assert len(found) == 0


@pytest.mark.asyncio
async def test_has_all(db):
await JSONBTestModel(data=json.dumps(dict(key1="foo", key3=2))).save()
await JSONBTestModel(data=json.dumps(dict(key2="bar"))).save()

found = await JSONBTestModel.objects.filter(
data__jsonb_has_all=array(["key1"])
).all()
assert len(found) == 1

found = await JSONBTestModel.objects.filter(
data__jsonb_has_all=array(["key1", "key2"])
).all()
assert len(found) == 0

found = await JSONBTestModel.objects.filter(
data__jsonb_has_all=array(["key1", "key3"])
).all()
assert len(found) == 1


@pytest.mark.asyncio
async def test_has_key_object(db):
await JSONBTestModel(data=json.dumps(dict(key1="foo"))).save()
Expand Down

0 comments on commit 2f48df4

Please sign in to comment.