d-maurer: Alessandro Pisa wrote at 2020-6-18 08:49 -0700:
>@ale-rt commented on this pull request.
>
>
>
>> @@ -3,8 +3,8 @@
>
> <main class="container-fluid">
>
>-    <dtml-let filterpath="REQUEST.get('filterpath', '/')"
>-              results="searchResults(path=filterpath)">
>+    <dtml-let filterpath="REQUEST.get('filterpath', '')"
>+              results="searchResults(path=filterpath) if filterpath else list(getAllBrains())">
>
>Isn't this a performance issue?

I have defined a new method `searchAll`.
It is similar to `getAllBrains` but returns a data type
like the other searches (`LazyMap`) instead of an interator.
I have replaced the expensive `list(getAllBrains())` with `searchAll()`.

diff --git a/CHANGES.rst b/CHANGES.rst
index a114bde..0437fe3 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,13 @@ Changelog
 5.2 (unreleased)
 ----------------
 
+- Add new method ``searchAll`` to perform a search for all documents.
+
+- Document ``getAllBrains`` and ``searchAll`` in the interface.
+
+- Update `catalogView.dtml` to changed behavior of empty searches
+  (`#102 <https://github.com/zopefoundation/Products.ZCatalog/issues/102>`_).
+
 - Fix case where index value is changed to None after previously being indexed.
   (`#100 <https://github.com/zopefoundation/Products.ZCatalog/issues/100>`_)
 
diff --git a/src/Products/ZCatalog/ZCatalog.py b/src/Products/ZCatalog/ZCatalog.py
index f1706f5..0bab3d9 100644
--- a/src/Products/ZCatalog/ZCatalog.py
+++ b/src/Products/ZCatalog/ZCatalog.py
@@ -44,6 +44,7 @@ import transaction
 from zExceptions import BadRequest
 from ZODB.POSException import ConflictError
 from zope.interface import implementer
+from ZTUtils.Lazy import LazyMap
 
 from Products.ZCatalog.Catalog import Catalog, CatalogError
 from Products.ZCatalog.interfaces import IZCatalog
@@ -566,6 +567,13 @@ class ZCatalog(Folder, Persistent, Implicit):
         for rid in self._catalog.data:
             yield self._catalog[rid]
 
+    @security.protected(search_zcatalog)
+    def searchAll(self):
+        # the result of a search for all documents
+        return LazyMap(self._catalog.__getitem__,
+                       self._catalog.data.keys(),
+                       len(self))
+
     @security.protected(search_zcatalog)
     def schema(self):
         return self._catalog.schema.keys()
diff --git a/src/Products/ZCatalog/dtml/catalogView.dtml b/src/Products/ZCatalog/dtml/catalogView.dtml
index c4d8cce..45c38b3 100644
--- a/src/Products/ZCatalog/dtml/catalogView.dtml
+++ b/src/Products/ZCatalog/dtml/catalogView.dtml
@@ -3,8 +3,8 @@
 
 <main class="container-fluid">
 
-    <dtml-let filterpath="REQUEST.get('filterpath', '/')"
-              results="searchResults(path=filterpath)">
+    <dtml-let filterpath="REQUEST.get('filterpath', '')"
+              results="searchResults(path=filterpath) if filterpath else searchAll()">
 <dtml-if results>
 
 <h1 class="form-label section-bar">Path filter</h1>
diff --git a/src/Products/ZCatalog/interfaces.py b/src/Products/ZCatalog/interfaces.py
index c4f72ef..d10022a 100644
--- a/src/Products/ZCatalog/interfaces.py
+++ b/src/Products/ZCatalog/interfaces.py
@@ -222,6 +222,12 @@ class IZCatalog(Interface):
         queries (even across catalogs) and merge and sort the combined results.
         """
 
+    def searchAll():
+        """the result of a search for all documents as a sequence."""
+
+    def getAllBrains():
+        """the result of a search for all documents as an iterator."""
+
     def refreshCatalog(clear=0, pghandler=None):
         """Reindex every object we can find, removing the unreachable
         ones from the index.

"dtml/catalogView.dtml" needs update to changed behavior for "empty" searches
This originally has been #101 .

`searchResults` has recently been changed regarding "empty" searches: formerly, an "empty" search returned all catalogued objects, now, it returns 0 results.

The above mentioned dtml file must be updated accordingly. Otherwise, the `Catalog` tab reports an empty catalog whenever the catalog lacks an index named `path`.
diff --git a/src/Products/ZCatalog/tests/test_zcatalog.py b/src/Products/ZCatalog/tests/test_zcatalog.py
index 04a5067..dee5678 100644
--- a/src/Products/ZCatalog/tests/test_zcatalog.py
+++ b/src/Products/ZCatalog/tests/test_zcatalog.py
@@ -19,6 +19,7 @@ from AccessControl import Unauthorized
 from Acquisition import Implicit
 import ExtensionClass
 from OFS.Folder import Folder as OFS_Folder
+from Testing.makerequest import makerequest
 
 
 class Folder(OFS_Folder):
@@ -275,6 +276,12 @@ class TestZCatalog(ZCatalogBase, unittest.TestCase):
             self.assertTrue(hasattr(brain, 'title'))
         self.assertEqual(len(brains), len(self._catalog))
 
+    def testSearchAll(self):
+        all = self._catalog.searchAll()
+        for b in all:
+            self.assertTrue(hasattr(b, 'title'))
+        self.assertEqual(len(all), len(self._catalog))
+
     # schema
     # indexes
     # index_objects
@@ -307,6 +314,16 @@ class TestZCatalog(ZCatalogBase, unittest.TestCase):
     # manage_setProgress
     # _getProgressThreshold
 
+    def test_catalogView(self):
+        catalog = makerequest(self._catalog)
+        # hack `getPhysicalPath` to avoid problem with the catalog plan
+        catalog.getPhysicalPath = None
+        # provide `ZopeVersion`
+        catalog.ZopeVersion = lambda *arg, **kw: 4
+        vr = catalog.manage_catalogView()
+        self.assertTrue("There are no objects in the Catalog." not in vr,
+                        "catalogView wrongly reports `no objects`")
+
 
 class TestAddDelColumnIndex(ZCatalogBase, unittest.TestCase):
 

pip install -e .
parse_log_pytest
pytest
pytest coverage
pip install setuptools zc.buildout
3.8
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
AccessControl==7.2
Acquisition==6.1
AuthEncoding==5.0
beautifulsoup4==4.13.3
BTrees==6.1
cffi==1.17.1
Chameleon==4.4.4
coverage==7.6.1
DateTime==5.5
DocumentTemplate==4.6
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
ExtensionClass==6.0
importlib_metadata==8.5.0
importlib_resources==6.4.5
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Missing==5.0
MultiMapping==5.0
multipart==1.2.1
packaging @ file:///croot/packaging_1720101850331/work
PasteDeploy==3.1.0
Persistence==5.1
persistent==6.1.1
pluggy @ file:///tmp/build/80754af9/pluggy_1648042571233/work
-e git+https://github.com/zopefoundation/Products.ZCatalog.git@c4e4cd55e17e2660e81795d4a8dc48278642a726#egg=Products.ZCatalog
pycparser==2.22
pytest @ file:///croot/pytest_1717793244625/work
python-gettext==5.0
pytz==2025.2
Record==4.1
RestrictedPython==7.4
roman==4.2
six==1.17.0
soupsieve==2.6
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
transaction==5.0
typing_extensions==4.13.0
waitress==3.0.0
WebOb==1.8.9
WebTest==3.0.1
WSGIProxy2==0.5.1
z3c.pt==4.4
zc.buildout==3.3
zc.lockfile==3.0.post1
ZConfig==4.1
zExceptions==5.0
zipp==3.20.2
ZODB==6.0
zodbpickle==4.1.1
Zope==5.12
zope.annotation==5.0
zope.browser==3.0
zope.browsermenu==5.0
zope.browserpage==5.0
zope.browserresource==5.1
zope.cachedescriptors==5.0
zope.component==6.0
zope.configuration==6.0
zope.container==6.1
zope.contentprovider==6.0
zope.contenttype==5.1
zope.datetime==5.0.0
zope.deferredimport==5.0
zope.deprecation==5.0
zope.dottedname==6.0
zope.event==5.0
zope.exceptions==5.2
zope.filerepresentation==6.0
zope.globalrequest==2.0
zope.hookable==7.0
zope.i18n==5.2
zope.i18nmessageid==7.0
zope.interface==7.2
zope.lifecycleevent==5.0
zope.location==5.0
zope.pagetemplate==5.1
zope.processlifetime==3.0
zope.proxy==6.1
zope.ptresource==5.0
zope.publisher==7.1
zope.schema==7.0.1
zope.security==7.3
zope.sequencesort==5.0
zope.site==5.0
zope.size==5.0
zope.structuredtext==5.0
zope.tal==5.0.1
zope.tales==6.0
zope.testbrowser==7.0.1
zope.testing==5.0.1
zope.traversing==5.0
zope.viewlet==5.0

name: Products.ZCatalog
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py38h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.1=py38h06a4308_0
  - pip=24.2=py38h06a4308_0
  - pluggy=1.0.0=py38h06a4308_1
  - pytest=7.4.4=py38h06a4308_0
  - python=3.8.20=he870216_0
  - readline=8.2=h5eee18b_0
  - setuptools=75.1.0=py38h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py38h06a4308_0
  - wheel=0.44.0=py38h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - accesscontrol==7.2
      - acquisition==6.1
      - authencoding==5.0
      - beautifulsoup4==4.13.3
      - btrees==6.1
      - cffi==1.17.1
      - chameleon==4.4.4
      - coverage==7.6.1
      - datetime==5.5
      - documenttemplate==4.6
      - extensionclass==6.0
      - importlib-metadata==8.5.0
      - importlib-resources==6.4.5
      - missing==5.0
      - multimapping==5.0
      - multipart==1.2.1
      - pastedeploy==3.1.0
      - persistence==5.1
      - persistent==6.1.1
      - pycparser==2.22
      - python-gettext==5.0
      - pytz==2025.2
      - record==4.1
      - restrictedpython==7.4
      - roman==4.2
      - six==1.17.0
      - soupsieve==2.6
      - transaction==5.0
      - typing-extensions==4.13.0
      - waitress==3.0.0
      - webob==1.8.9
      - webtest==3.0.1
      - wsgiproxy2==0.5.1
      - z3c-pt==4.4
      - zc-buildout==3.3
      - zc-lockfile==3.0.post1
      - zconfig==4.1
      - zexceptions==5.0
      - zipp==3.20.2
      - zodb==6.0
      - zodbpickle==4.1.1
      - zope==5.12
      - zope-annotation==5.0
      - zope-browser==3.0
      - zope-browsermenu==5.0
      - zope-browserpage==5.0
      - zope-browserresource==5.1
      - zope-cachedescriptors==5.0
      - zope-component==6.0
      - zope-configuration==6.0
      - zope-container==6.1
      - zope-contentprovider==6.0
      - zope-contenttype==5.1
      - zope-datetime==5.0.0
      - zope-deferredimport==5.0
      - zope-deprecation==5.0
      - zope-dottedname==6.0
      - zope-event==5.0
      - zope-exceptions==5.2
      - zope-filerepresentation==6.0
      - zope-globalrequest==2.0
      - zope-hookable==7.0
      - zope-i18n==5.2
      - zope-i18nmessageid==7.0
      - zope-interface==7.2
      - zope-lifecycleevent==5.0
      - zope-location==5.0
      - zope-pagetemplate==5.1
      - zope-processlifetime==3.0
      - zope-proxy==6.1
      - zope-ptresource==5.0
      - zope-publisher==7.1
      - zope-schema==7.0.1
      - zope-security==7.3
      - zope-sequencesort==5.0
      - zope-site==5.0
      - zope-size==5.0
      - zope-structuredtext==5.0
      - zope-tal==5.0.1
      - zope-tales==6.0
      - zope-testbrowser==7.0.1
      - zope-testing==5.0.1
      - zope-traversing==5.0
      - zope-viewlet==5.0
prefix: /opt/conda/envs/Products.ZCatalog

src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testSearchAll src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::test_catalogView
src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testBooleanEvalOn_manage_catalogObject src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testBooleanEvalOn_refreshCatalog_getobject src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testCall src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testGetAllBrains src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testGetIndexDataForUID src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testGetMetadataForUID src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testReindexIndexDoesntDoMetadata src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testReindexIndexesFalse src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testSearch src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testSearchNot src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testSearchResults src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::testUpdateMetadata src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::test_getobject_traversal src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::test_interfaces src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalog::test_len src/Products/ZCatalog/tests/test_zcatalog.py::TestAddDelColumnIndex::testAddColumn src/Products/ZCatalog/tests/test_zcatalog.py::TestAddDelColumnIndex::testAddIndex src/Products/ZCatalog/tests/test_zcatalog.py::TestAddDelColumnIndex::testClearIndex src/Products/ZCatalog/tests/test_zcatalog.py::TestAddDelColumnIndex::testDelColumn src/Products/ZCatalog/tests/test_zcatalog.py::TestAddDelColumnIndex::testDelIndex src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_getObject_found src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_getObject_missing_raises_NotFound src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_getObject_restricted_raises_Unauthorized src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_unrestrictedGetObject_found src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_unrestrictedGetObject_missing_raises_NotFound src/Products/ZCatalog/tests/test_zcatalog.py::TestZCatalogGetObject::test_unrestrictedGetObject_restricted
src/Products/ZCatalog/dtml/catalogView.dtml src/Products/ZCatalog/ZCatalog.py CHANGES.rst src/Products/ZCatalog/interfaces.py
src/Products/ZCatalog/dtml/catalogView.dtml src/Products/ZCatalog/ZCatalog.py CHANGES.rst src/Products/ZCatalog/interfaces.py