Skip to content

Commit cb258ce

Browse files
committed
HStoreRef: a simple annotation expression to select individual hstore keys
1 parent 7aa1c23 commit cb258ce

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

psqlextra/expressions.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,35 @@ def relabeled_clone(self, relabels):
5454
self.hstore_key,
5555
self.output_field
5656
)
57+
58+
59+
class HStoreRef(expressions.F):
60+
"""Inline reference to a HStore key.
61+
62+
Allows selecting individual keys in annotations.
63+
"""
64+
65+
def __init__(self, name: str, key: str):
66+
"""Initializes a new instance of :see:HStoreRef.
67+
68+
Arguments:
69+
name:
70+
The name of the column/field to resolve.
71+
72+
key:
73+
The name of the HStore key to select.
74+
"""
75+
76+
super().__init__(name)
77+
self.key = key
78+
79+
def resolve_expression(self, *args, **kwargs) -> HStoreColumn:
80+
"""Resolves the expression into a :see:HStoreColumn expression."""
81+
82+
original_expression = super().resolve_expression(*args, **kwargs)
83+
expression = HStoreColumn(
84+
original_expression.alias,
85+
original_expression.target,
86+
self.key
87+
)
88+
return expression

tests/test_hstore_field.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.db import models
22

33
from psqlextra import HStoreField
4+
from psqlextra.expressions import HStoreRef
45

56
from .fake_model import get_fake_model
67

@@ -46,3 +47,31 @@ def test_values():
4647
result = list(model.objects.values_list('title__en', 'title__ar'))[0]
4748
assert result[0] == obj.title['en']
4849
assert result[1] == obj.title['ar']
50+
51+
result = list(model.objects.values_list('title__en', 'title__ar'))[0]
52+
53+
def test_annotate_ref():
54+
"""Tests whether annotating using a :see:HStoreRef expression
55+
works correctly.
56+
57+
This allows you to select an individual hstore key."""
58+
59+
model_fk = get_fake_model({
60+
'title': HStoreField(),
61+
})
62+
63+
model = get_fake_model({
64+
'fk': models.ForeignKey(model_fk)
65+
})
66+
67+
fk = model_fk.objects.create(title={'en': 'english', 'ar': 'arabic'})
68+
obj = model.objects.create(fk=fk)
69+
70+
queryset = (
71+
model.objects
72+
.annotate(english_title=HStoreRef('fk__title', 'en'))
73+
.values('english_title')
74+
.first()
75+
)
76+
77+
assert queryset['english_title'] == 'english'

0 commit comments

Comments
 (0)