Coverage for mindsdb / api / http / namespaces / views.py: 88%

97 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1from http import HTTPStatus 

2 

3from flask import request 

4from flask_restx import Resource 

5 

6from mindsdb.api.http.utils import http_error 

7from mindsdb.api.http.namespaces.configs.projects import ns_conf 

8from mindsdb.api.executor.controllers.session_controller import SessionController 

9from mindsdb.metrics.metrics import api_endpoint_metrics 

10from mindsdb.utilities.exception import EntityNotExistsError 

11 

12 

13@ns_conf.route("/<project_name>/views") 

14class ViewsList(Resource): 

15 @ns_conf.doc("list_views") 

16 @api_endpoint_metrics("GET", "/views") 

17 def get(self, project_name): 

18 """List all views""" 

19 session = SessionController() 

20 try: 

21 project = session.database_controller.get_project(project_name) 

22 except EntityNotExistsError: 

23 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist") 

24 

25 all_views = project.get_views() 

26 all_view_objs = [] 

27 # Only want to return relevant fields to the user. 

28 for view in all_views: 

29 all_view_objs.append({"id": view["metadata"]["id"], "name": view["name"], "query": view["query"]}) 

30 return all_view_objs 

31 

32 @ns_conf.doc("create_view") 

33 @api_endpoint_metrics("POST", "/views") 

34 def post(self, project_name): 

35 """Create a new view""" 

36 if "view" not in request.json: 

37 return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", 'Must provide "view" parameter in POST body') 

38 session = SessionController() 

39 view_obj = request.json["view"] 

40 if "name" not in view_obj: 

41 return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", 'Missing "name" field for view') 

42 if "query" not in view_obj: 

43 return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", 'Missing "query" field for view') 

44 name = view_obj["name"] 

45 query = view_obj["query"] 

46 

47 try: 

48 project = session.database_controller.get_project(project_name) 

49 except EntityNotExistsError: 

50 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist") 

51 

52 if project.get_view(name) is not None: 

53 return http_error(HTTPStatus.CONFLICT, "Name conflict", f"View with name {name} already exists.") 

54 

55 project.create_view(name, query, session) 

56 created_view = project.get_view(name) 

57 # Only want to return relevant fields to the user. 

58 return { 

59 "id": created_view["metadata"]["id"], 

60 "name": created_view["name"], 

61 "query": created_view["query"], 

62 }, HTTPStatus.CREATED 

63 

64 

65@ns_conf.route("/<project_name>/views/<view_name>") 

66@ns_conf.param("project_name", "Name of the project") 

67@ns_conf.param("view_name", "Name of the view") 

68class ViewResource(Resource): 

69 @ns_conf.doc("get_view") 

70 @api_endpoint_metrics("GET", "/views/view") 

71 def get(self, project_name, view_name): 

72 """Get a view by name""" 

73 session = SessionController() 

74 try: 

75 project = session.database_controller.get_project(project_name) 

76 except EntityNotExistsError: 

77 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist") 

78 

79 view = project.get_view(view_name) 

80 if view is None: 

81 return http_error(HTTPStatus.NOT_FOUND, "View not found", f"View with name {view_name} does not exist") 

82 

83 # Only want to return relevant fields to the user. 

84 return {"id": view["metadata"]["id"], "name": view["name"], "query": view["query"]} 

85 

86 @ns_conf.doc("update_view") 

87 @api_endpoint_metrics("PUT", "/views/view") 

88 def put(self, project_name, view_name): 

89 """Updates or creates a view""" 

90 if "view" not in request.json: 

91 return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", 'Must provide "view" parameter in PUT body') 

92 request_view = request.json["view"] 

93 session = SessionController() 

94 try: 

95 project = session.database_controller.get_project(project_name) 

96 except EntityNotExistsError: 

97 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist") 

98 

99 existing_view = project.get_view(view_name) 

100 if existing_view is None: 

101 # Create 

102 if "query" not in request_view: 102 ↛ 103line 102 didn't jump to line 103 because the condition on line 102 was never true

103 return http_error(HTTPStatus.BAD_REQUEST, "Wrong argument", 'Missing "query" field for new view') 

104 project.create_view(view_name, request_view["query"], session) 

105 created_view = project.get_view(view_name) 

106 # Only want to return relevant fields to the user. 

107 return { 

108 "id": created_view["metadata"]["id"], 

109 "name": created_view["name"], 

110 "query": created_view["query"], 

111 }, HTTPStatus.CREATED 

112 

113 new_query = existing_view["query"] 

114 if "query" in request_view: 114 ↛ 118line 114 didn't jump to line 118 because the condition on line 114 was always true

115 new_query = request_view["query"] 

116 project.update_view(view_name, new_query) 

117 

118 existing_view = project.get_view(view_name) 

119 # Only want to return relevant fields to the user. 

120 return {"id": existing_view["metadata"]["id"], "name": existing_view["name"], "query": existing_view["query"]} 

121 

122 @ns_conf.doc("delete_view") 

123 @api_endpoint_metrics("DELETE", "/views/view") 

124 def delete(self, project_name, view_name): 

125 """Deletes a view by name""" 

126 session = SessionController() 

127 try: 

128 project = session.database_controller.get_project(project_name) 

129 except EntityNotExistsError: 

130 return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist") 

131 

132 if project.get_view(view_name) is None: 

133 return http_error(HTTPStatus.NOT_FOUND, "View not found", f"View with name {view_name} does not exist") 

134 

135 project.delete_view(view_name) 

136 return "", HTTPStatus.NO_CONTENT