Coverage for gws-app/gws/base/search/finder.py: 78%
77 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
1from typing import Optional, cast
3import gws
4import gws.base.model
5import gws.base.template
6import gws.base.shape
7import gws.config.util
8import gws.lib.uom
11class SpatialContext(gws.Enum):
12 """Spatial context for keyword searches."""
14 map = 'map'
15 """Search in the map extent."""
16 view = 'view'
17 """Search in the client view extent."""
20class Config(gws.ConfigWithAccess):
21 """Finder configuration."""
23 models: Optional[list[gws.ext.config.model]]
24 """Data models for features."""
25 spatialContext: Optional[SpatialContext] = SpatialContext.map
26 """Spatial context for keyword searches."""
27 templates: Optional[list[gws.ext.config.template]]
28 """Feature formatting templates."""
29 title: Optional[str]
30 """Finder title."""
31 category: Optional[str]
32 """Category for the finder. (added in 8.2)"""
33 withGeometry: bool = True
34 """Enable geometry search."""
35 withKeyword: bool = True
36 """Enable keyword search."""
37 withFilter: bool = True
38 """Enable filter search."""
41class Object(gws.Finder):
42 spatialContext: SpatialContext
44 def configure(self):
45 self.templates = []
46 self.models = []
48 self.withKeyword = self.cfg('withKeyword', default=True)
49 self.withGeometry = self.cfg('withGeometry', default=True)
50 self.withFilter = self.cfg('withFilter', default=True)
52 self.spatialContext = self.cfg('spatialContext', default=SpatialContext.map)
53 self.title = self.cfg('title', default='')
54 self.category = self.cfg('category', default='')
56 ##
58 def configure_models(self):
59 return gws.config.util.configure_models_for(self)
61 def configure_templates(self):
62 return gws.config.util.configure_templates_for(self)
64 ##
66 def can_run(self, search, user):
67 has_param = False
69 if search.keyword:
70 if not self.supportsKeywordSearch or not self.withKeyword:
71 gws.log.debug(f'can run: False: {self} {search.keyword=} {self.supportsKeywordSearch=} {self.withKeyword=}')
72 return False
73 has_param = True
75 if search.shape:
76 if not self.supportsGeometrySearch or not self.withGeometry:
77 gws.log.debug(f'can run: False: {self} <shape> {self.supportsGeometrySearch=} {self.withGeometry=}')
78 return False
79 has_param = True
81 if search.filter:
82 if not self.supportsFilterSearch or not self.withFilter:
83 gws.log.debug(f'can run: False: {self} {search.filter=} {self.supportsFilterSearch=} {self.withFilter=}')
84 return False
85 has_param = True
87 return has_param
89 def context_shape(self, search: gws.SearchQuery) -> gws.Shape:
90 if search.shape:
91 return search.shape
92 if self.spatialContext == SpatialContext.view and search.bounds:
93 return gws.base.shape.from_bounds(search.bounds)
94 if search.project:
95 return gws.base.shape.from_bounds(search.project.map.bounds)
97 def run(self, search, user, layer=None):
98 model = self.root.app.modelMgr.find_model(self, layer, user=user, access=gws.Access.read)
99 if not model:
100 gws.log.debug(f'no model for {user.uid=} in finder {self.uid!r}')
101 return []
102 search = cast(gws.SearchQuery, gws.u.merge(search, shape=self.context_shape(search)))
103 mc = gws.ModelContext(op=gws.ModelOperation.read, target=gws.ModelReadTarget.searchResults, user=user)
104 return model.find_features(search, mc)