Coverage for gws-app/gws/base/search/action.py: 0%

68 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-17 01:37 +0200

1"""Search API.""" 

2 

3from typing import Optional 

4 

5import gws 

6import gws.base.model 

7import gws.base.action 

8import gws.base.template 

9import gws.base.feature 

10import gws.base.shape 

11import gws.lib.uom 

12 

13gws.ext.new.action('search') 

14 

15_DEFAULT_VIEWS = ['title', 'teaser', 'description'] 

16_DEFAULT_TOLERANCE = 50, gws.Uom.px 

17 

18 

19class Config(gws.base.action.Config): 

20 """Search action""" 

21 

22 limit: int = 1000 

23 """search results limit""" 

24 tolerance: Optional[gws.UomValueStr] 

25 """default tolerance""" 

26 

27 

28class Props(gws.base.action.Props): 

29 pass 

30 

31 

32class Request(gws.Request): 

33 crs: Optional[gws.CrsName] 

34 extent: Optional[gws.Extent] 

35 keyword: str = '' 

36 layerUids: list[str] 

37 limit: Optional[int] 

38 resolution: float 

39 shapes: Optional[list[gws.base.shape.Props]] 

40 tolerance: Optional[str] 

41 views: Optional[list[str]] 

42 

43 

44class Response(gws.Response): 

45 features: list[gws.FeatureProps] 

46 

47 

48class Object(gws.base.action.Object): 

49 limit = 0 

50 tolerance: gws.UomValue 

51 

52 def configure(self): 

53 self.limit = self.cfg('limit') 

54 self.tolerance = self.cfg('tolerance') or _DEFAULT_TOLERANCE 

55 

56 @gws.ext.command.api('searchFind') 

57 def find(self, req: gws.WebRequester, p: Request) -> Response: 

58 """Perform a search""" 

59 

60 return Response(features=self._get_features(req, p)) 

61 

62 def _get_features(self, req: gws.WebRequester, p: Request) -> list[gws.FeatureProps]: 

63 

64 project = req.user.require_project(p.projectUid) 

65 search = gws.SearchQuery(project=project) 

66 

67 if p.layerUids: 

68 search.layers = gws.u.compact(req.user.acquire(uid, gws.ext.object.layer) for uid in p.layerUids) 

69 

70 search.bounds = project.map.bounds 

71 if p.extent: 

72 search.bounds = gws.Bounds(crs=p.crs or project.map.bounds.crs, extent=p.extent) 

73 

74 search.limit = self.limit 

75 if p.limit: 

76 search.limit = min(int(p.limit), self.limit) 

77 

78 if p.shapes: 

79 shapes = [gws.base.shape.from_props(s) for s in p.shapes] 

80 search.shape = shapes[0] if len(shapes) == 1 else shapes[0].union(shapes[1:]) 

81 

82 search.tolerance = self.tolerance 

83 if p.tolerance: 

84 search.tolerance = gws.lib.uom.parse(p.tolerance, gws.Uom.px) 

85 

86 if p.resolution: 

87 search.resolution = p.resolution 

88 

89 if p.keyword.strip(): 

90 search.keyword = p.keyword.strip() 

91 

92 results = self.root.app.searchMgr.run_search(search, req.user) 

93 if not results: 

94 return [] 

95 

96 mc = gws.ModelContext( 

97 op=gws.ModelOperation.read, 

98 target=gws.ModelReadTarget.searchResults, 

99 project=project, 

100 user=req.user 

101 ) 

102 

103 for res in results: 

104 templates = gws.u.compact( 

105 self.root.app.templateMgr.find_template(f'feature.{v}', where=[res.finder, res.layer, project], user=req.user) 

106 for v in p.views or _DEFAULT_VIEWS 

107 ) 

108 res.feature.render_views(templates, user=req.user, project=project, layer=res.layer) 

109 

110 return [res.feature.model.feature_to_view_props(res.feature, mc) for res in results]