Skip to content

Commit

Permalink
Merge pull request #64 from Princeton-CDH/chore/item_type_dynamicfield
Browse files Browse the repository at this point in the history
Rename item_type field to item_type_s everywhere and document the change
  • Loading branch information
rlskoeser committed May 12, 2021
2 parents 6f7656b + 246e125 commit d9e999d
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 63 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ CHANGELOG
* bugfix: in some cases, index script was wrongly detecting ModelIndexable
subclasses as abstract and excluding them; this has been corrected
* ModelIndexable now extends `django.db.models.Model`; existing code
should be updated to avoid double-extending Model
MUST be updated to avoid double-extending Model
* Default index data has been updated to use a dynamic field `item_type_s` instead of `item_type` so that basic setup does not require customizing the solr schema.

0.6.1
-----
Expand Down
2 changes: 1 addition & 1 deletion parasolr/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def index_data(self):
:meth:`index_item_type` """
return {
'id': self.index_id(),
'item_type': self.index_item_type()
'item_type_s': self.index_item_type()
}

def index(self):
Expand Down
2 changes: 1 addition & 1 deletion parasolr/management/commands/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def clear(self, mode):
del_query = '*:*'
else:
# construct query based on item type
del_query = 'item_type:%s' % mode
del_query = 'item_type_s:%s' % mode

if self.verbosity >= self.v_normal:
# pluralize indexable names but not all
Expand Down
18 changes: 9 additions & 9 deletions parasolr/query/queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Filter, search and sort methods return a new queryset, and can be
chained. For example::
SolrQuerySet(solrclient).filter(item_type='person') \
SolrQuerySet(solrclient).filter(item_type_s='person') \
.search(name='hem*') \
.order_by('sort_name') \
Expand Down Expand Up @@ -277,7 +277,7 @@ def _lookup_to_filter(key: str, value: Any, tag: str = '') -> str:
# for any value and double-negates a lookup
# for the requested values
# The final output is something like:
# -(item_type:[* TO *] OR item_type:(book OR periodical))
# -(item_type_s:[* TO *] OR item_type_s:(book OR periodical))
solr_query = '-(%s:%s OR -%s)' % \
(key, SolrQuerySet.ANY_VALUE, solr_query)

Expand All @@ -304,13 +304,13 @@ def filter(self, *args, tag: str = '', **kwargs) -> 'SolrQuerySet':
method call, or they can be chained for the same effect.
For example::
queryset.filter(item_type='person').filter(birth_year=1900)
queryset.filter(item_type='person', birth_year=1900)
queryset.filter(item_type_s='person').filter(birth_year=1900)
queryset.filter(item_type_s='person', birth_year=1900)
A tag may be specified for the filter to be used with facet.field
exclusions::
queryset.filter(item_type='person', tag='person')
queryset.filter(item_type_s='person', tag='person')
To provide a filter that should be used unmodified, provide
the exact string of your filter query::
Expand All @@ -320,8 +320,8 @@ def filter(self, *args, tag: str = '', **kwargs) -> 'SolrQuerySet':
You can also search for pre-defined using lookups on a field,
for example::
queryset.filter(item_type__in=['person', 'book'])
queryset.filter(item_type__exists=False)
queryset.filter(item_type_s__in=['person', 'book'])
queryset.filter(item_type_s__exists=False)
Currently supported field lookups:
Expand Down Expand Up @@ -354,9 +354,9 @@ def facet(self, *args: str, **kwargs) -> 'SolrQuerySet':
For example::
qs = queryset.facet('person_type', 'age')
qs = qs.facet('item_type')
qs = qs.facet('item_type_s')
would result in ``item_type`` being the only facet field.
would result in ``item_type_s`` being the only facet field.
"""
qs_copy = self._clone()

Expand Down
98 changes: 49 additions & 49 deletions parasolr/query/tests/test_queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ def test_query_opts(self):
sqs.start = 10
sqs.stop = 20
sqs.sort_options = ['title asc', 'date desc']
sqs.filter_qs = ['item_type:work']
sqs.filter_qs = ['item_type_s:work']
sqs.search_qs = ['title:reading', 'author:johnson']
sqs.field_list = ['title', 'author', 'date:pubyear_i']
sqs.highlight_field = 'content'
sqs.highlight_opts = {'snippets': 3, 'method': 'unified'}
sqs.facet_field_list = ['item_type', 'member_type']
sqs.facet_field_list = ['item_type_s', 'member_type']
sqs.facet_opts = {'sort': 'count'}
sqs.stats_field_list = ['item_type', 'account_start_i']
sqs.stats_field_list = ['item_type_s', 'account_start_i']
# check that both prepended and not get stats. prefix appropriately
sqs.stats_opts = {'calcdistinct': True, 'stats.facet': 'mean'}
query_opts = sqs.query_opts()
Expand Down Expand Up @@ -248,7 +248,7 @@ def test_filter(self):
sqs = SolrQuerySet(mocksolr)

# arg options added to filter list as is
new_filters = ['item_type:work', 'date:[1550 TO 1900]']
new_filters = ['item_type_s:work', 'date:[1550 TO 1900]']
filtered_qs = sqs.filter(*new_filters)
# returned queryset has the filters
assert filtered_qs.filter_qs == new_filters
Expand All @@ -257,26 +257,26 @@ def test_filter(self):

# keyword arg options converted into filters, except tag, which
# is prepended as a special case.
filtered_qs = sqs.filter(item_type='work', date=1500, tag='workDate')
filtered_qs = sqs.filter(item_type_s='work', date=1500, tag='workDate')
# returned queryset has the filters
assert '{!tag=workDate}item_type:work' in filtered_qs.filter_qs
assert '{!tag=workDate}item_type_s:work' in filtered_qs.filter_qs
assert '{!tag=workDate}date:1500' in filtered_qs.filter_qs
# original queryset is unchanged
assert not sqs.filter_qs

# chaining adds to the filters, tag is optional and not appended
# if not supplied
filtered_qs = sqs.filter(item_type='work').filter(date=1500) \
filtered_qs = sqs.filter(item_type_s='work').filter(date=1500) \
.filter('name:he*')
assert 'item_type:work' in filtered_qs.filter_qs
assert 'item_type_s:work' in filtered_qs.filter_qs
assert 'date:1500' in filtered_qs.filter_qs
assert 'name:he*' in filtered_qs.filter_qs

def test_facet(self):
mocksolr = Mock(spec=SolrClient)
sqs = SolrQuerySet(mocksolr)
# facet a search
facet_list = ['person_type', 'item_type']
facet_list = ['person_type', 'item_type_s']
faceted_qs = sqs.facet(*facet_list)
# faceting should be set
assert faceted_qs.facet_field_list == facet_list
Expand Down Expand Up @@ -368,23 +368,23 @@ def test_search(self):
sqs = SolrQuerySet(mocksolr)

# arg options added to filter list as is
queries = ['item_type:work', 'date:[1550 TO *]']
queries = ['item_type_s:work', 'date:[1550 TO *]']
search_sqs = sqs.search(*queries)
# returned queryset has the filters
assert search_sqs.search_qs == queries
# original queryset is unchanged
assert not sqs.search_qs

# keyword arg options are converted
search_sqs = sqs.search(item_type='work', date=1550)
assert 'item_type:work' in search_sqs.search_qs
search_sqs = sqs.search(item_type_s='work', date=1550)
assert 'item_type_s:work' in search_sqs.search_qs
assert 'date:1550' in search_sqs.search_qs
# original queryset is unchanged
assert not sqs.search_qs

# chaining is additive
search_sqs = sqs.search(item_type='work').search(date=1550)
assert 'item_type:work' in search_sqs.search_qs
search_sqs = sqs.search(item_type_s='work').search(date=1550)
assert 'item_type_s:work' in search_sqs.search_qs
assert 'date:1550' in search_sqs.search_qs
# original queryset is unchanged
assert not sqs.search_qs
Expand Down Expand Up @@ -544,9 +544,9 @@ def test_none(self):
assert sqs.search_qs == []

# none after search terms replaces the search
search_sqs = SolrQuerySet(mocksolr).search('item_type:work')
search_sqs = SolrQuerySet(mocksolr).search('item_type_s:work')
none_sqs = search_sqs.none()
assert search_sqs.search_qs == ['item_type:work']
assert search_sqs.search_qs == ['item_type_s:work']
assert none_sqs.search_qs == ['NOT *:*']

def test__clone(self):
Expand All @@ -565,9 +565,9 @@ def test__clone(self):
assert cloned_sqs.stats_opts == {}

# set everything
custom_sqs = sqs.filter(item_type='person').search(name='he*') \
.order_by('birth_year').facet('item_type')\
.stats('item_type')
custom_sqs = sqs.filter(item_type_s='person').search(name='he*') \
.order_by('birth_year').facet('item_type_s')\
.stats('item_type_s')
custom_sqs.set_limits(10, 100)
custom_clone = custom_sqs._clone()
assert custom_clone.start == 10
Expand Down Expand Up @@ -599,61 +599,61 @@ class CustomSolrQuerySet(SolrQuerySet):

# sanity-check chaining
sqs = SolrQuerySet(mocksolr)
filtered_sqs = sqs.filter(item_type='person')
filtered_sqs = sqs.filter(item_type_s='person')
# filter should be set
assert 'item_type:person' in filtered_sqs.filter_qs
assert 'item_type_s:person' in filtered_sqs.filter_qs
sorted_sqs = filtered_sqs.order_by('birth_year')
# sort and filter should be set
assert 'item_type:person' in sorted_sqs.filter_qs
assert 'item_type_s:person' in sorted_sqs.filter_qs
assert 'birth_year asc' in sorted_sqs.sort_options
search_sqs = sorted_sqs.search(name='hem*')
# search , sort, and filter should be set
assert 'item_type:person' in search_sqs.filter_qs
assert 'item_type_s:person' in search_sqs.filter_qs
assert 'birth_year asc' in search_sqs.sort_options
assert 'name:hem*' in search_sqs.search_qs

def test__lookup_to_filter(self):
# simple key-value
assert SolrQuerySet._lookup_to_filter('item_type', 'work') == \
'item_type:work'
assert SolrQuerySet._lookup_to_filter('item_type_s', 'work') == \
'item_type_s:work'
# exists
assert SolrQuerySet._lookup_to_filter('item_type__exists', True) == \
'item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__exists', True) == \
'item_type_s:[* TO *]'
# does not exist
assert SolrQuerySet._lookup_to_filter('item_type__exists', False) == \
'-item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__exists', False) == \
'-item_type_s:[* TO *]'
# simple __in query
assert SolrQuerySet._lookup_to_filter('item_type__in', ['a', 'b']) == \
'item_type:(a OR b)'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['a', 'b']) == \
'item_type_s:(a OR b)'
# complex __in query with a negation
assert SolrQuerySet._lookup_to_filter('item_type__in', ['a', 'b', '']) == \
'-(item_type:[* TO *] OR -item_type:(a OR b))'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['a', 'b', '']) == \
'-(item_type_s:[* TO *] OR -item_type_s:(a OR b))'
# __in query with just a negation
assert SolrQuerySet._lookup_to_filter('item_type__in', ['']) == \
'-item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['']) == \
'-item_type_s:[* TO *]'

# test cases with tag
# simple key-value
assert SolrQuerySet._lookup_to_filter('item_type', 'work', tag='type') == \
'{!tag=type}item_type:work'
assert SolrQuerySet._lookup_to_filter('item_type_s', 'work', tag='type') == \
'{!tag=type}item_type_s:work'
# exists
assert SolrQuerySet._lookup_to_filter('item_type__exists', True, tag='type') == \
'{!tag=type}item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__exists', True, tag='type') == \
'{!tag=type}item_type_s:[* TO *]'
# does not exist
assert SolrQuerySet._lookup_to_filter('item_type__exists', False, tag='type') == \
'{!tag=type}-item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__exists', False, tag='type') == \
'{!tag=type}-item_type_s:[* TO *]'
# in list query with tag
assert SolrQuerySet._lookup_to_filter('item_type__in', ['a', 'b'], tag='type') == \
'{!tag=type}item_type:(a OR b)'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['a', 'b'], tag='type') == \
'{!tag=type}item_type_s:(a OR b)'
# in list query with a None value
assert SolrQuerySet._lookup_to_filter('item_type__in', ['a', 'b', None]) == \
'-(item_type:[* TO *] OR -item_type:(a OR b))'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['a', 'b', None]) == \
'-(item_type_s:[* TO *] OR -item_type_s:(a OR b))'
# in list query with a negation
assert SolrQuerySet._lookup_to_filter('item_type__in', ['a', 'b', ''], tag='type') == \
'{!tag=type}-(item_type:[* TO *] OR -item_type:(a OR b))'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', ['a', 'b', ''], tag='type') == \
'{!tag=type}-(item_type_s:[* TO *] OR -item_type_s:(a OR b))'
# in list query with only a negation
assert SolrQuerySet._lookup_to_filter('item_type__in', [''], tag='type') == \
'{!tag=type}-item_type:[* TO *]'
assert SolrQuerySet._lookup_to_filter('item_type_s__in', [''], tag='type') == \
'{!tag=type}-item_type_s:[* TO *]'
# range query - start and end
assert SolrQuerySet._lookup_to_filter('year__range', (1900, 2000)) == \
'year:[1900 TO 2000]'
Expand Down
2 changes: 1 addition & 1 deletion parasolr/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def test_clear(self):

cmd.solr.reset_mock()
cmd.clear('work')
cmd.solr.update.delete_by_query.assert_called_with('item_type:work')
cmd.solr.update.delete_by_query.assert_called_with('item_type_s:work')

cmd.solr.reset_mock()
cmd.clear('foo')
Expand Down
2 changes: 1 addition & 1 deletion parasolr/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_index_data(self, mocksolr):
model = MockModelIndexable()
data = model.index_data()
assert data['id'] == model.index_id()
assert data['item_type'] == model.index_item_type()
assert data['item_type_s'] == model.index_item_type()
assert len(data) == 2

def test_index(self, mocksolr):
Expand Down

0 comments on commit d9e999d

Please sign in to comment.