New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Not indexed value support (MissingValue, EmptyValue) #74
Open
andbag
wants to merge
49
commits into
master
Choose a base branch
from
notindexed_value_support
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
2f56826
Initial not indexed value support (MissingValue, EmptyValue)
andbag 29b0bf3
Reorganize NotIndexedValue classes
andbag ce61b42
Fix BTree TypeError
andbag 05c8079
Add not indexed value tests
andbag 2de46a3
Fix get_object_datum for not indexed value support
andbag c61afae
Add additional tests for not indexed value support
andbag a47ebc7
Fix EmptyValue support
andbag d140ffb
Disable Missing/EmptyValue interface of CompositeIndex
andbag 7f246be
Fix flake8
andbag a0c8546
Merge branch 'master' into notindexed_value_support
0f6a2ce
Merge branch 'master' into notindexed_value_support
7c9cf99
Merge branch 'master' into notindexed_value_support
a2a1ee7
New naming of methods and variables
andbag 6ceb6dc
Store special values in `_unindex`
andbag 7b9313c
Fix KeywordIndex tests
andbag 0911a0c
Fix unindex and refactor KeywordIndex
andbag 47d5b95
Return False for SpecialValues on truth value testing
andbag e305aca
Fix flake8
andbag 8e47c81
Merge branch 'master' into notindexed_value_support
b529bd2
Raise Error if multiple indexed attributes are set
andbag 6b7b84d
Prepare index_object for multiple indexed attributes
andbag 52114da
Merge branch 'fix_indexed_attr' into notindexed_value_support
andbag b494b75
Add test for multiple indexed attributes
andbag e319a05
Replace __nonzero__ with __bool__ for py3
andbag bcbd74d
Store keywords always as OOset
andbag 5f709ac
Fix tests for OOset
andbag 5f6c287
Create debug entry if datum for attribute cannot be determined
andbag 0c5493a
Fix consistent check for missing `_unindex` entry
andbag 090bc9e
Remove obsolete code
andbag e7c5e07
flake8
andbag cf950e6
Fix clearing of special values of KexwordIndex
andbag 78efffb
Continue to fix clearing of special values
andbag 7dd55b7
Add definition map for special values
andbag 0d58199
Refinement of special value support
andbag 6d5fa3e
Fix test for empty value
andbag 4110f65
Log then ignore keys not indexable
andbag 2815927
Consolidate code
andbag 2a45691
Avoid obsolete type casting
andbag 6c5e52c
Consolidate special value handling step one
andbag fd0a9d2
Consolidate special value handling step two
andbag 225df14
Consolidate code of CompositeIndex
andbag 9bbfdfb
Completion of interfaces
andbag 906a858
Code further generalized
andbag ab99560
flake8
andbag e595088
Continue cleaning
andbag d059521
Code further generalized II
andbag 9883352
Reorganize code and complete tests
andbag 62321b9
Fix for py2 backward compatibility
andbag 3913a78
Merge branch 'master' into notindexed_value_support
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,16 +21,31 @@ | |
from Acquisition import aq_parent | ||
from Acquisition import aq_inner | ||
from App.special_dtml import DTMLFile | ||
from BTrees.OOBTree import difference | ||
from BTrees.OOBTree import OOSet | ||
from Persistence import PersistentMapping | ||
from zope.interface import implementer | ||
|
||
from Products.PluginIndexes.interfaces import ITransposeQuery | ||
from zope.interface import implementer_only | ||
|
||
from Products.PluginIndexes.interfaces import ( | ||
ILimitedResultIndex, | ||
IQueryIndex, | ||
ISortIndex, | ||
IUniqueValueIndex, | ||
IRequestCacheIndex, | ||
ITransposeQuery, | ||
missing, | ||
empty, | ||
) | ||
from Products.PluginIndexes.util import safe_callable | ||
from Products.PluginIndexes.KeywordIndex.KeywordIndex import KeywordIndex | ||
from Products.PluginIndexes.unindex import _marker | ||
from Products.ZCatalog.query import IndexQuery | ||
|
||
try: | ||
basestring | ||
except NameError: | ||
# Python 3 compatibility | ||
basestring = (bytes, str) | ||
|
||
LOG = logging.getLogger('CompositeIndex') | ||
|
||
QUERY_OPTIONS = { | ||
|
@@ -172,7 +187,8 @@ def __repr__(self): | |
'attributes: {0.attributes}>').format(self) | ||
|
||
|
||
@implementer(ITransposeQuery) | ||
@implementer_only(ILimitedResultIndex, IQueryIndex, IUniqueValueIndex, | ||
ISortIndex, IRequestCacheIndex, ITransposeQuery) | ||
class CompositeIndex(KeywordIndex): | ||
|
||
"""Index for composition of simple fields. | ||
|
@@ -209,45 +225,8 @@ def __init__(self, id, ignore_ex=None, call_methods=None, | |
c_attributes) | ||
self.clear() | ||
|
||
def _index_object(self, documentId, obj, threshold=None, attr=''): | ||
|
||
# get permuted keywords | ||
newKeywords = self._get_permuted_keywords(obj) | ||
|
||
oldKeywords = self._unindex.get(documentId, None) | ||
|
||
if oldKeywords is None: | ||
# we've got a new document, let's not futz around. | ||
try: | ||
for kw in newKeywords: | ||
self.insertForwardIndexEntry(kw, documentId) | ||
if newKeywords: | ||
self._unindex[documentId] = list(newKeywords) | ||
except TypeError: | ||
return 0 | ||
else: | ||
# we have an existing entry for this document, and we need | ||
# to figure out if any of the keywords have actually changed | ||
if type(oldKeywords) is not OOSet: | ||
oldKeywords = OOSet(oldKeywords) | ||
newKeywords = OOSet(newKeywords) | ||
fdiff = difference(oldKeywords, newKeywords) | ||
rdiff = difference(newKeywords, oldKeywords) | ||
if fdiff or rdiff: | ||
# if we've got forward or reverse changes | ||
if newKeywords: | ||
self._unindex[documentId] = list(newKeywords) | ||
else: | ||
del self._unindex[documentId] | ||
if fdiff: | ||
self.unindex_objectKeywords(documentId, fdiff) | ||
if rdiff: | ||
for kw in rdiff: | ||
self.insertForwardIndexEntry(kw, documentId) | ||
return 1 | ||
|
||
def _get_permuted_keywords(self, obj): | ||
""" returns permutation tuple of object keywords """ | ||
def get_object_datum(self, obj, attr): | ||
""" returns permutation of object keywords """ | ||
|
||
components = self.getIndexComponents() | ||
kw_list = [] | ||
|
@@ -270,34 +249,48 @@ def _get_permuted_keywords(self, obj): | |
p = combinations(c, r) | ||
pkl.extend(p) | ||
|
||
return tuple(pkl) | ||
return OOSet(pkl) | ||
|
||
def _get_component_datum(self, obj, attr): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This almost looks like |
||
# self.id is the name of the index, which is also the name of the | ||
# attribute we're interested in. If the attribute is callable, | ||
# we'll do so. | ||
try: | ||
datum = getattr(obj, attr) | ||
if safe_callable(datum): | ||
datum = datum() | ||
except (AttributeError, TypeError): | ||
datum = _marker | ||
return datum | ||
|
||
def _get_component_keywords(self, obj, component): | ||
|
||
if component.meta_type == 'FieldIndex': | ||
# last attribute is the winner if value is not None | ||
for attr in component.attributes: | ||
datum = self._get_object_datum(obj, attr) | ||
datum = self._get_component_datum(obj, attr) | ||
if datum is None: | ||
continue | ||
if datum is None: | ||
return () | ||
if isinstance(datum, list): | ||
datum = tuple(datum) | ||
if isinstance(datum, (list, OOSet)): | ||
return tuple(datum) | ||
return (datum,) | ||
|
||
elif component.meta_type == 'KeywordIndex': | ||
# last attribute is the winner | ||
attr = component.attributes[-1] | ||
datum = self._get_object_keywords(obj, attr) | ||
datum = self._get_component_datum(obj, attr) | ||
if isinstance(datum, basestring): | ||
datum = (datum,) | ||
if isinstance(datum, list): | ||
datum = tuple(datum) | ||
return datum | ||
|
||
elif component.meta_type == 'BooleanIndex': | ||
# last attribute is the winner | ||
attr = component.attributes[-1] | ||
datum = self._get_object_datum(obj, attr) | ||
datum = self._get_component_datum(obj, attr) | ||
if datum is not _marker: | ||
datum = int(bool(datum)) | ||
return (datum,) | ||
|
@@ -380,6 +373,14 @@ def make_query(self, query): | |
if c.meta_type == 'BooleanIndex': | ||
rec.keys = [int(bool(v)) for v in rec.keys[:]] | ||
|
||
# cannot currently support KeywordIndex's | ||
# missing/empty feature | ||
if c.meta_type == 'KeywordIndex': | ||
if missing in rec.keys: | ||
continue | ||
if empty in rec.keys: | ||
continue | ||
|
||
# rec with 'not' parameter | ||
not_parm = rec.get('not', None) | ||
if not_parm: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having used similar code for Python 2/3 compatibility, I have been directed to use
six
instead. Consistently usingsix
for Python 2/3 compatibility will facilitate code cleanup once Python 2 support is dropped.