Skip to content

Commit

Permalink
Merge pull request #8 from plone/feature/7
Browse files Browse the repository at this point in the history
Support allow multi value results for virtual paths.
  • Loading branch information
jensens authored Dec 12, 2018
2 parents a98837f + 3a8d78f commit 27a4127
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 45 deletions.
9 changes: 4 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
language: python
sudo: false
dist: xenial
python:
- 2.7
- 3.4
- 3.5
- 3.6
- 3.7
install:
- pip install six==1.10.0 # force here to avoid conflict with zc.recipe.testrunner
- pip install -U setuptools==33.1.1
- pip install -U setuptools pip
- pip install zc.buildout
- buildout bootstrap
- buildout annotate
- buildout
script:
- bin/test -v1
Expand Down
7 changes: 5 additions & 2 deletions Products/ExtendedPathIndex/ExtendedPathIndex.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class ExtendedPathIndex(PathIndex):
)

indexed_attrs = None
multi_valued = False
query_options = ("query", "level", "operator",
"depth", "navtree", "navtree_start")

Expand All @@ -62,8 +63,10 @@ def __init__(self, id, extra=None, caller=None):

if isinstance(extra, dict):
attrs = extra.get('indexed_attrs', None)
self.multi_valued = extra.get('multi_valued', False)
else:
attrs = getattr(extra, 'indexed_attrs', None)
self.multi_valued = getattr(extra, 'multi_valued', False)

if attrs is None:
return
Expand Down Expand Up @@ -245,7 +248,7 @@ def search(self, path, default_level=0, depth=-1, navtree=0,
# Optimized absolute path navtree and breadcrumbs cases
result = []
add = lambda x: x is not None and result.append(x)
if depth == 1:
if depth == 1 and not self.multi_valued:
# Navtree case, all sibling elements along the path
convert = multiunion
index = self._index_parents
Expand All @@ -261,7 +264,7 @@ def search(self, path, default_level=0, depth=-1, navtree=0,

if not path.startswith('/'):
path = '/' + path
if depth == 0:
if depth == 0 and not self.multi_valued:
# Specific object search
res = self._index_items.get(path)
return res and IISet([res]) or IISet()
Expand Down
98 changes: 67 additions & 31 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
Introduction
============

This is an index that supports depth limiting, and the ability to build a
structure usable for navtrees and sitemaps. The actual navtree implementations
are not (and should not) be in this Product, this is the index implementation
only.
This is an Zope Catalog index to query treeish structures in the ZODB by path.
It supports depth limiting, and has the ability to build a structure usable for navtrees and sitemaps.
The actual navtree implementations are not (and should not) be in this package.
This is the index implementation only.

Assumptions
===========

EPI makes an assumption about the catalog and index being in the
same container as all the content. This makes a lot of sense in a
Plone setting, but might not work as expected in other scenarios.
EPI makes an assumption about the catalog and index being in the same container as all the content.
This makes a lot of sense in a Plone setting, but might not work as expected in other scenarios.

A query like ``/plonesite/folder, level=0`` is transformed internally to
``/folder, level=1``. This avoids touching the rather large plonesite set
which contains reference to all content in your site.
A query like ``/plonesite/folder, level=0`` is transformed internally to ``/folder, level=1``.
This avoids touching the rather large plonesite set which contains reference to all content in your site.

Features
========
Expand All @@ -24,6 +22,44 @@ Features

- Can construct a navigation tree with a single catalog query

Configuration
=============

In a GenericSetup profile, provide th following snippet to create an index::

<index
meta_type="ExtendedPathIndex"
name="my_path">
<extra
name="indexed_attrs"
value="my_path"
/>
</index>

For multi valued paths, provide an extra
(switches off an breaking optimization not needed for this cases)::

<index
meta_type="ExtendedPathIndex"
name="my_path">
<extra
name="indexed_attrs"
value="my_path"
/>
<extra
name="multi_valued"
value="True"
/>
</index>

An example for an index with multiple values per path element:
Imagine to index multilingual content.
Every item is translated and all translated items share a common unique identifier
(this is how plone.app.multilingual works).
Now create an indexer returing this unique identifier instead of the items ID as a path element.
With this it is possible to query all elements of all languages in a folder in one go
(for an advanced usage of this pattern look at ``plone.app.multilingualindexes``).

Usage
=====

Expand All @@ -32,45 +68,45 @@ Usage

``catalog(path=dict(query='some/path', depth=0))``
search for the object with the given path.
For multi valued paths, multiple objects are returned.

``catalog(path=dict(query='some/path', depth=2))``
search for all objects below some/path but only down to a depth of 2

``catalog(path=dict(query='some/path', navtree=True))``
search for all objects below some/path for rendering a navigation tree. This
includes all objects below some/path up to a depth of 1 and all parent
objects.
search for all objects below some/path for rendering a navigation tree.
This includes all objects below some/path up to a depth of 1 and all parent objects.

``catalog(path=dict(query='some/path', navtree=True, depth=0))``
search for all objects below some/path for rendering a breadcrumb trail.
This includes only the parent objects themselves.

``catalog(path=dict(query='some/path', navtree=True, navtree_start=1))``
search for all objects below some/path for rendering a partial
navigation tree. This includes all objects below the path but stops
1 level above the root. The given path is included, even if it is at a
shorter path in the portal than the level parameter would allow.
search for all objects below some/path for rendering a partial navigation tree.
This includes all objects below the path but stops 1 level above the root.
The given path is included,
even if it is at a shorter path in the portal than the level parameter would allow.

``catalog(path=dict(query='some/path', navtree=True, depth=0, navtree_start=1))``
search for all objects below some/path for rendering a partial
breadcrumb trail. This includes all parents below the path but stops
1 level above the root. The given path is included, even if it is at a
lower level in the portal than the start parameter would allow.
search for all objects below some/path for rendering a partial breadcrumb trail.
This includes all parents below the path but stops 1 level above the root.
The given path is included, even if it is at a lower level in the portal than the start parameter would allow.

``catalog(path=dict(query='some/path', level=2))``
search for all objects whose path contains some/path at level 2. This
includes paths like /foo/bar/some/path and /spam/eggs/some/path, plus all
children of those paths.
search for all objects whose path contains some/path at level 2.
This includes paths like /foo/bar/some/path and /spam/eggs/some/path,
plus all children of those paths.

``catalog(path=dict(query='some/path', level=-1, depth=0))``
search for all objects whose path contains some/path at *any* level. This
includes paths like /spam/some/path as well as /foo/bar/baz/some/path, but
only those exact matches are included in the result because depth is set to
0.
search for all objects whose path contains some/path at *any* level.
This includes paths like /spam/some/path as well as /foo/bar/baz/some/path,
but only those exact matches are included in the result because depth is set to 0.

``catalog(path=dict(query=(('foo/bar', 2), ('bar/baz'), 1), depth=0))``
search for multiple paths, each at different levels (foo/bar at level 2,
and bar/baz at level 1), and return exact matches only.
search for multiple paths,
each at different levels
(foo/bar at level 2, and bar/baz at level 1),
and return exact matches only.

Credits
=======
Expand All @@ -87,5 +123,5 @@ Credits
License
=======

This software is released under the GPL license.
This software is released under the GPLv2 license.

2 changes: 2 additions & 0 deletions news/7-feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Support allow multi value results for "virtual" paths.
[jensens]
15 changes: 8 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from setuptools import setup, find_packages

version = '3.3.2.dev0'
version = '3.4.0.dev0'

setup(
name='Products.ExtendedPathIndex',
version=version,
description="Zope catalog index for paths",
long_description=(open("README.rst").read() + "\n" + \
open("CHANGES.rst").read()),
long_description=(
open("README.rst").read() +
"\n" +
open("CHANGES.rst").read()
),
classifiers=[
"Environment :: Web Environment",
"Framework :: Plone",
Expand All @@ -19,11 +22,9 @@
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
],
],
keywords='Zope catalog index',
author='Plone Foundation',
author_email='plone-developers@lists.sourceforge.net',
Expand All @@ -41,4 +42,4 @@
'Zope2 >= 2.13.0a3',
'zope.interface',
],
)
)

0 comments on commit 27a4127

Please sign in to comment.