Coverage for mindsdb / interfaces / database / views.py: 47%

70 statements  

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

1from sqlalchemy import func 

2from mindsdb.interfaces.storage import db 

3from mindsdb.interfaces.query_context.context_controller import query_context_controller 

4from mindsdb.utilities.context import context as ctx 

5from mindsdb.utilities.exception import EntityExistsError, EntityNotExistsError 

6from mindsdb.interfaces.model.functions import get_project_record, get_project_records 

7 

8 

9class ViewController: 

10 def add(self, name, query, project_name): 

11 from mindsdb.interfaces.database.database import DatabaseController 

12 

13 database_controller = DatabaseController() 

14 project_databases_dict = database_controller.get_dict(filter_type="project") 

15 

16 if project_name not in project_databases_dict: 16 ↛ 17line 16 didn't jump to line 17 because the condition on line 16 was never true

17 raise EntityNotExistsError("Can not find project", project_name) 

18 

19 project_id = project_databases_dict[project_name]["id"] 

20 view_record = ( 

21 db.session.query(db.View.id) 

22 .filter(db.View.name == name, db.View.company_id == ctx.company_id, db.View.project_id == project_id) 

23 .first() 

24 ) 

25 if view_record is not None: 25 ↛ 26line 25 didn't jump to line 26 because the condition on line 25 was never true

26 raise EntityExistsError("View already exists", name) 

27 

28 view_record = db.View(name=name, company_id=ctx.company_id, query=query, project_id=project_id) 

29 db.session.add(view_record) 

30 db.session.commit() 

31 

32 def update(self, name: str, query: str, project_name: str, strict_case: bool = False): 

33 """Update the SQL query of an existing view in the specified project. 

34 

35 Args: 

36 name (str): The name of the view to update. 

37 query (str): The new SQL query for the view. 

38 project_name (str): The name of the project containing the view. 

39 strict_case (bool, optional): If True, the view name is case-sensitive. If False, the name comparison is case-insensitive. Defaults to False. 

40 

41 Raises: 

42 EntityNotExistsError: If the view with the specified name does not exist in the given project. 

43 

44 Returns: 

45 None 

46 """ 

47 project_record = get_project_record(project_name) 

48 

49 q = db.session.query(db.View).filter( 

50 db.View.company_id == ctx.company_id, db.View.project_id == project_record.id 

51 ) 

52 if strict_case: 52 ↛ 53line 52 didn't jump to line 53 because the condition on line 52 was never true

53 q = q.filter(db.View.name == name) 

54 else: 

55 q = q.filter(func.lower(db.View.name) == func.lower(name)) 

56 

57 rec = q.first() 

58 if rec is None: 58 ↛ 59line 58 didn't jump to line 59 because the condition on line 58 was never true

59 raise EntityNotExistsError("View not found", name) 

60 rec.query = query 

61 db.session.commit() 

62 

63 def delete(self, name: str, project_name: str, strict_case: bool = False) -> None: 

64 """Remove a view with the specified name from the given project. 

65 

66 Args: 

67 name (str): The name of the view to remove. 

68 project_name (str): The name of the project containing the view. 

69 strict_case (bool, optional): If True, the view name is case-sensitive. Defaults to False. 

70 

71 Raises: 

72 EntityNotExistsError: If the view does not exist. 

73 

74 Returns: 

75 None 

76 """ 

77 project_record = get_project_record(project_name) 

78 

79 query = db.session.query(db.View).filter( 

80 db.View.company_id == ctx.company_id, db.View.project_id == project_record.id 

81 ) 

82 if strict_case: 82 ↛ 83line 82 didn't jump to line 83 because the condition on line 82 was never true

83 query = query.filter(db.View.name == name) 

84 else: 

85 query = query.filter(func.lower(db.View.name) == func.lower(name)) 

86 

87 record = query.first() 

88 if record is None: 88 ↛ 89line 88 didn't jump to line 89 because the condition on line 88 was never true

89 raise EntityNotExistsError("View not found", name) 

90 db.session.delete(record) 

91 db.session.commit() 

92 

93 query_context_controller.drop_query_context("view", record.id) 

94 

95 def list(self, project_name): 

96 project_names = {} 

97 for project in get_project_records(): 

98 if project_name is not None and project.name != project_name: 

99 continue 

100 project_names[project.id] = project.name 

101 

102 query = db.session.query(db.View).filter( 

103 db.View.company_id == ctx.company_id, db.View.project_id.in_(list(project_names.keys())) 

104 ) 

105 

106 data = [] 

107 

108 for record in query: 

109 data.append( 

110 { 

111 "id": record.id, 

112 "name": record.name, 

113 "project": project_names[record.project_id], 

114 "query": record.query, 

115 } 

116 ) 

117 

118 return data 

119 

120 def _get_view_record_data(self, record): 

121 return {"id": record.id, "name": record.name, "query": record.query} 

122 

123 def get(self, id=None, name=None, project_name=None): 

124 project_record = get_project_record(project_name) 

125 

126 if id is not None: 

127 records = ( 

128 db.session.query(db.View) 

129 .filter_by(id=id, project_id=project_record.id, company_id=ctx.company_id) 

130 .all() 

131 ) 

132 elif name is not None: 

133 records = ( 

134 db.session.query(db.View) 

135 .filter( 

136 func.lower(db.View.name) == name.lower(), 

137 db.View.project_id == project_record.id, 

138 db.View.company_id == ctx.company_id, 

139 ) 

140 .all() 

141 ) 

142 if len(records) == 0: 

143 if name is None: 

144 name = f"id={id}" 

145 raise EntityNotExistsError("Can't find view", f"{project_name}.{name}") 

146 elif len(records) > 1: 

147 raise Exception(f"There are multiple views with name/id: {name}/{id}") 

148 record = records[0] 

149 return self._get_view_record_data(record)