Skip to content
This repository was archived by the owner on Sep 30, 2019. It is now read-only.

Commit 47f0ef3

Browse files
committed
ranks raise exception if lookup isnt valid
1 parent 96d91a6 commit 47f0ef3

File tree

4 files changed

+54
-25
lines changed

4 files changed

+54
-25
lines changed

pg_fts/fields.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class TSVectorBaseField(Field):
3939
:raises: exceptions.FieldError if lookup isn't tsquery, search or isearch
4040
4141
"""
42-
42+
valid_lookups = ('search', 'isearch', 'tsquery')
4343
empty_strings_allowed = True
4444

4545
def __init__(self, dictionary='english', **kwargs):
@@ -58,7 +58,7 @@ def db_type(self, connection):
5858
def get_db_prep_lookup(self, lookup_type, value, connection,
5959
prepared=False):
6060

61-
if lookup_type not in ('search', 'isearch', 'tsquery'):
61+
if lookup_type not in self.valid_lookups:
6262
raise exceptions.FieldError("'%s' isn't valid Lookup for %s" % (
6363
lookup_type, self.__class__.__name__))
6464

pg_fts/ranks.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from django.db.models.fields import FloatField
88
from django.db.models.constants import LOOKUP_SEP
99
from django.db.models.sql import aggregates
10+
from django.core import exceptions
11+
from pg_fts.fields import TSVectorBaseField
1012

1113
__all__ = ('FTSRankCd', 'FTSRank', 'FTSRankDictionay', 'FTSRankCdDictionary')
1214

@@ -52,7 +54,7 @@ def as_sql(self, qn, connection):
5254
return self.sql_template % substitutions, [self.params]
5355

5456

55-
class Aggregate(object):
57+
class RankBase(object):
5658
NORMALIZATION = (0, 1, 2, 4, 8, 16, 32)
5759
sql_function, rhs, dictionary, srt_lookup = '', '', '', ''
5860

@@ -114,9 +116,13 @@ def _do_checks(self):
114116
', '.join('%d' % i for i in self.NORMALIZATION))
115117
assert len(self.extra) == 1, 'to many arguments for %s' % (
116118
self.__class__.__name__)
119+
if self.srt_lookup not in TSVectorBaseField.valid_lookups:
120+
raise exceptions.FieldError(
121+
"The '%s' isn't valid Lookup for %s" % (
122+
self.srt_lookup, self.__class__.__name__))
117123

118124

119-
class FTSRank(Aggregate):
125+
class FTSRank(RankBase):
120126
"""
121127
Interface for PostgreSQL ts_rank
122128
@@ -146,6 +152,9 @@ class FTSRank(Aggregate):
146152
:param weights: iterable float
147153
148154
:returns: rank
155+
156+
:raises: exceptions.FieldError if lookup isn't valid
157+
149158
"""
150159

151160
name = 'FTSRank'
@@ -157,10 +166,10 @@ def __init__(self, **extra):
157166
self.weights = extra.pop('weights', [])
158167
params = tuple(extra.items())[0]
159168
self.extra = extra
160-
self._do_checks()
161169
lookups, self.rhs = params[0].split(LOOKUP_SEP), params[1]
162170
self.srt_lookup = lookups[-1]
163171
self.lookup = LOOKUP_SEP.join(lookups[:-1])
172+
self._do_checks()
164173

165174

166175
class FTSRankCd(FTSRank):
@@ -180,6 +189,8 @@ class FTSRankCd(FTSRank):
180189
181190
:returns: rank_cd
182191
192+
:raises: exceptions.FieldError if lookup isn't valid
193+
183194
Example::
184195
185196
Article.objects.annotate(
@@ -216,6 +227,8 @@ class FTSRankDictionay(FTSRank):
216227
217228
:returns: rank
218229
230+
:raises: exceptions.FieldError if lookup isn't valid
231+
219232
Example::
220233
221234
Article.objects.annotate(
@@ -239,10 +252,10 @@ def __init__(self, **extra):
239252
self.weights = extra.pop('weights', [])
240253
params = tuple(extra.items())[0]
241254
self.extra, self.rhs = extra, params[1]
242-
self._do_checks()
243255
lookups = params[0].split(LOOKUP_SEP)
244256
self.dictionary, self.srt_lookup = lookups[-2:]
245257
self.lookup = LOOKUP_SEP.join(lookups[:-2])
258+
self._do_checks()
246259

247260

248261
class FTSRankCdDictionary(FTSRankDictionay):
@@ -260,6 +273,8 @@ class FTSRankCdDictionary(FTSRankDictionay):
260273
261274
:returns: rank_cd
262275
276+
:raises: exceptions.FieldError if lookup isn't valid
277+
263278
Example::
264279
265280
Article.objects.annotate(

testapp/tests/test_annotation.py

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,24 @@ def test_rank_assertions(self):
140140
)
141141
list(qs)
142142

143+
# need to find a way to catch FieldError raised by
144+
# django.db.models.sql.query in add fields
145+
#
146+
def test_transform_dictionary_exception(self):
147+
with self.assertRaises(exceptions.FieldError) as msg:
148+
TSQueryModel.objects.annotate(
149+
rank=FTSRank(tsvector__nodict='malucos')),
150+
self.assertEqual(
151+
str(msg.exception),
152+
"The 'nodict' isn't valid Lookup for FTSRank")
153+
154+
with self.assertRaises(exceptions.FieldError) as msg:
155+
TSQueryModel.objects.annotate(
156+
rank=FTSRank(tsvector='malucos')),
157+
self.assertEqual(
158+
str(msg.exception),
159+
"The 'tsvector' isn't valid Lookup for FTSRank")
160+
143161
def test_ts_rank_cd_search(self):
144162
q = TSQueryModel.objects.annotate(
145163
rank=FTSRankCd(tsvector__search='para mesmo')
@@ -268,21 +286,18 @@ def test_rank_cd_dictionary(self):
268286
self.assertIn('''ts_rank_cd("testapp_tsmultidicmodel"."tsvector", to_tsquery('portuguese', para & os)) AS "rank"''',
269287
str(qn_pt.query))
270288

271-
# need to find a way to catch FieldError raised by
272-
# django.db.models.sql.query in add fields
273-
#
274-
# def test_transform_dictionary_exception(self):
275-
# with self.assertRaises(exceptions.FieldError) as msg:
276-
# TSMultidicModel.objects.annotate(
277-
# rank=FTSRankDictionay(tsvector__nodict='malucos')),
278-
# self.assertEqual(
279-
# str(msg.exception),
280-
# "The 'nodict' is not in testapp.TSMultidicModel.dictionary choices")
281-
282-
# def test_transform_exception(self):
283-
# with self.assertRaises(exceptions.FieldError) as msg:
284-
# list(TSMultidicModel.objects.annotate(
285-
# rank=FTSRankDictionay(tsvector__portuguese='malucos')))
286-
# self.assertEqual(
287-
# str(msg.exception),
288-
# "'exact' isn't valid Lookup for TSVectorBaseField")
289+
def test_transform_dictionary_exception(self):
290+
with self.assertRaises(exceptions.FieldError) as msg:
291+
TSMultidicModel.objects.annotate(
292+
rank=FTSRankDictionay(tsvector__nodict='malucos')),
293+
self.assertEqual(
294+
str(msg.exception),
295+
"The 'nodict' isn't valid Lookup for FTSRankDictionay")
296+
297+
def test_transform_exception(self):
298+
with self.assertRaises(exceptions.FieldError) as msg:
299+
list(TSMultidicModel.objects.annotate(
300+
rank=FTSRankDictionay(tsvector__portuguese='malucos')))
301+
self.assertEqual(
302+
str(msg.exception),
303+
"The 'portuguese' isn't valid Lookup for FTSRankDictionay")

testapp/tests/test_migrations.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ def test_sql_migrate_creates_vector_field_multi(self):
125125
"UPDATE testapp_tsvectormodel SET tsvector = setweight(to_tsvector(dictionary::regconfig, COALESCE(title, '')), 'D') || setweight(to_tsvector(dictionary::regconfig, COALESCE(body, '')), 'D');",
126126
stdout.getvalue())
127127

128-
129128
@override_system_checks([])
130129
@override_settings(MIGRATION_MODULES={"testapp": "testapp.migrations_multidict"})
131130
def test_sql_fts_index_multi(self):

0 commit comments

Comments
 (0)