Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
feat: JSONB has key
Browse files Browse the repository at this point in the history
  • Loading branch information
Chart.js committed Oct 4, 2022
1 parent d45a156 commit c80bea6
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ 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_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.

```python
await JSONBTestModel.objects.filter(data__jsonb_has_key="key1").all()
```

#### Array

Array field requires a bit more setup to pass the type of the array into the field
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,10 +26,22 @@ def jsonb_contains(self, other: Any) -> ormar.queryset.clause.FilterGroup:
return self._select_operator(op="jsonb_contains", other=other)


def jsonb_has_key(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_key", other=other)


# Need to patch the filter objects to support JSONB specifc actions
FIELD_ACCESSOR_MAP = [
("jsonb_contained_by", jsonb_contained_by),
("jsonb_contains", jsonb_contains),
("jsonb_has_key", jsonb_has_key),
]


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

for (ormar_operation, pg_operation) in ACCESSOR_MAP:
Expand Down
24 changes: 24 additions & 0 deletions tests/fields/test_jsonb.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,27 @@ async def test_contained_by(db):
data__jsonb_contains=dict(key1="bar")
).all()
assert len(found) == 0


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

found = await JSONBTestModel.objects.filter(data__jsonb_has_key="key1").all()
assert len(found) == 1

found = await JSONBTestModel.objects.filter(data__jsonb_has_key="key3").all()
assert len(found) == 0


@pytest.mark.asyncio
async def test_has_key_array(db):
await JSONBTestModel(data=json.dumps(["foo"])).save()
await JSONBTestModel(data=json.dumps(["bar"])).save()

found = await JSONBTestModel.objects.filter(data__jsonb_has_key="foo").all()
assert len(found) == 1

found = await JSONBTestModel.objects.filter(data__jsonb_has_key="other").all()
assert len(found) == 0

0 comments on commit c80bea6

Please sign in to comment.