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
« 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
9class ViewController:
10 def add(self, name, query, project_name):
11 from mindsdb.interfaces.database.database import DatabaseController
13 database_controller = DatabaseController()
14 project_databases_dict = database_controller.get_dict(filter_type="project")
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)
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)
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()
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.
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.
41 Raises:
42 EntityNotExistsError: If the view with the specified name does not exist in the given project.
44 Returns:
45 None
46 """
47 project_record = get_project_record(project_name)
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))
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()
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.
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.
71 Raises:
72 EntityNotExistsError: If the view does not exist.
74 Returns:
75 None
76 """
77 project_record = get_project_record(project_name)
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))
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()
93 query_context_controller.drop_query_context("view", record.id)
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
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 )
106 data = []
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 )
118 return data
120 def _get_view_record_data(self, record):
121 return {"id": record.id, "name": record.name, "query": record.query}
123 def get(self, id=None, name=None, project_name=None):
124 project_record = get_project_record(project_name)
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)