MindsDB 25.5.4.1__py3-none-any.whl → 25.6.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of MindsDB might be problematic. Click here for more details.

Files changed (70) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/api/a2a/agent.py +28 -25
  3. mindsdb/api/a2a/common/server/server.py +32 -26
  4. mindsdb/api/a2a/run_a2a.py +1 -1
  5. mindsdb/api/executor/command_executor.py +69 -14
  6. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +49 -65
  7. mindsdb/api/executor/datahub/datanodes/project_datanode.py +29 -48
  8. mindsdb/api/executor/datahub/datanodes/system_tables.py +35 -61
  9. mindsdb/api/executor/planner/plan_join.py +67 -77
  10. mindsdb/api/executor/planner/query_planner.py +176 -155
  11. mindsdb/api/executor/planner/steps.py +37 -12
  12. mindsdb/api/executor/sql_query/result_set.py +45 -64
  13. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +14 -18
  14. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +17 -18
  15. mindsdb/api/executor/sql_query/steps/insert_step.py +13 -33
  16. mindsdb/api/executor/sql_query/steps/subselect_step.py +43 -35
  17. mindsdb/api/executor/utilities/sql.py +42 -48
  18. mindsdb/api/http/namespaces/config.py +1 -1
  19. mindsdb/api/http/namespaces/file.py +14 -23
  20. mindsdb/api/mysql/mysql_proxy/data_types/mysql_datum.py +12 -28
  21. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +59 -50
  22. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/resultset_row_package.py +9 -8
  23. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +449 -461
  24. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +87 -36
  25. mindsdb/integrations/handlers/file_handler/file_handler.py +15 -9
  26. mindsdb/integrations/handlers/file_handler/tests/test_file_handler.py +43 -24
  27. mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +10 -3
  28. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +26 -33
  29. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +74 -51
  30. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +305 -98
  31. mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +53 -34
  32. mindsdb/integrations/handlers/salesforce_handler/salesforce_tables.py +136 -6
  33. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +334 -83
  34. mindsdb/integrations/libs/api_handler.py +261 -57
  35. mindsdb/integrations/libs/base.py +100 -29
  36. mindsdb/integrations/utilities/files/file_reader.py +99 -73
  37. mindsdb/integrations/utilities/handler_utils.py +23 -8
  38. mindsdb/integrations/utilities/sql_utils.py +35 -40
  39. mindsdb/interfaces/agents/agents_controller.py +196 -192
  40. mindsdb/interfaces/agents/constants.py +7 -1
  41. mindsdb/interfaces/agents/langchain_agent.py +42 -11
  42. mindsdb/interfaces/agents/mcp_client_agent.py +29 -21
  43. mindsdb/interfaces/data_catalog/__init__.py +0 -0
  44. mindsdb/interfaces/data_catalog/base_data_catalog.py +54 -0
  45. mindsdb/interfaces/data_catalog/data_catalog_loader.py +359 -0
  46. mindsdb/interfaces/data_catalog/data_catalog_reader.py +34 -0
  47. mindsdb/interfaces/database/database.py +81 -57
  48. mindsdb/interfaces/database/integrations.py +220 -234
  49. mindsdb/interfaces/database/log.py +72 -104
  50. mindsdb/interfaces/database/projects.py +156 -193
  51. mindsdb/interfaces/file/file_controller.py +21 -65
  52. mindsdb/interfaces/knowledge_base/controller.py +63 -10
  53. mindsdb/interfaces/knowledge_base/evaluate.py +519 -0
  54. mindsdb/interfaces/knowledge_base/llm_client.py +75 -0
  55. mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +83 -43
  56. mindsdb/interfaces/skills/skills_controller.py +54 -36
  57. mindsdb/interfaces/skills/sql_agent.py +109 -86
  58. mindsdb/interfaces/storage/db.py +223 -79
  59. mindsdb/migrations/versions/2025-05-28_a44643042fe8_added_data_catalog_tables.py +118 -0
  60. mindsdb/migrations/versions/2025-06-09_608e376c19a7_updated_data_catalog_data_types.py +58 -0
  61. mindsdb/utilities/config.py +9 -2
  62. mindsdb/utilities/log.py +35 -26
  63. mindsdb/utilities/ml_task_queue/task.py +19 -22
  64. mindsdb/utilities/render/sqlalchemy_render.py +129 -181
  65. mindsdb/utilities/starters.py +49 -1
  66. {mindsdb-25.5.4.1.dist-info → mindsdb-25.6.2.0.dist-info}/METADATA +268 -268
  67. {mindsdb-25.5.4.1.dist-info → mindsdb-25.6.2.0.dist-info}/RECORD +70 -62
  68. {mindsdb-25.5.4.1.dist-info → mindsdb-25.6.2.0.dist-info}/WHEEL +0 -0
  69. {mindsdb-25.5.4.1.dist-info → mindsdb-25.6.2.0.dist-info}/licenses/LICENSE +0 -0
  70. {mindsdb-25.5.4.1.dist-info → mindsdb-25.6.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,34 @@
1
+ from mindsdb.interfaces.data_catalog.base_data_catalog import BaseDataCatalog
2
+ from mindsdb.interfaces.storage import db
3
+
4
+
5
+ class DataCatalogReader(BaseDataCatalog):
6
+ """
7
+ This class is responsible for reading the metadata from the data catalog and providing it in a structured format.
8
+ """
9
+
10
+ def read_metadata_as_string(self) -> str:
11
+ """
12
+ Read the metadata from the data catalog and return it as a string.
13
+ """
14
+ if not self.is_data_catalog_supported():
15
+ return f"Data catalog is not supported for database '{self.database_name}'."
16
+ tables = self._read_metadata()
17
+ if not tables:
18
+ self.logger.warning(f"No metadata found for database '{self.database_name}'")
19
+ return f"No metadata found for database '{self.database_name}'"
20
+ metadata_str = "Data Catalog: \n"
21
+ for table in tables:
22
+ metadata_str += table.as_string() + "\n\n"
23
+ return metadata_str
24
+
25
+ def _read_metadata(self) -> list:
26
+ """
27
+ Read the metadata from the data catalog and return it in a structured format.
28
+ """
29
+ query = db.session.query(db.MetaTables).filter_by(integration_id=self.integration_id)
30
+ if self.table_names:
31
+ cleaned_table_names = [name.strip("`").split(".")[-1] for name in self.table_names]
32
+ query = query.filter(db.MetaTables.name.in_(cleaned_table_names))
33
+ tables = query.all()
34
+ return tables
@@ -11,6 +11,7 @@ from mindsdb.interfaces.database.log import LogDBController
11
11
  class DatabaseController:
12
12
  def __init__(self):
13
13
  from mindsdb.interfaces.database.integrations import integration_controller
14
+
14
15
  self.integration_controller = integration_controller
15
16
  self.project_controller = ProjectController()
16
17
 
@@ -21,13 +22,13 @@ class DatabaseController:
21
22
  databases = self.get_dict()
22
23
  name = name.lower()
23
24
  if name not in databases:
24
- raise EntityNotExistsError('Database does not exists', name)
25
- db_type = databases[name]['type']
26
- if db_type == 'project':
25
+ raise EntityNotExistsError("Database does not exists", name)
26
+ db_type = databases[name]["type"]
27
+ if db_type == "project":
27
28
  project = self.get_project(name)
28
29
  project.delete()
29
30
  return
30
- elif db_type == 'data':
31
+ elif db_type == "data":
31
32
  self.integration_controller.delete(name)
32
33
  return
33
34
  else:
@@ -37,59 +38,52 @@ class DatabaseController:
37
38
  def get_list(self, filter_type: Optional[str] = None, with_secrets: Optional[bool] = True):
38
39
  projects = self.project_controller.get_list()
39
40
  integrations = self.integration_controller.get_all(show_secrets=with_secrets)
40
- result = [{
41
- 'name': 'information_schema',
42
- 'type': 'system',
43
- 'id': None,
44
- 'engine': None,
45
- 'visible': True,
46
- 'deletable': False
47
- }, {
48
- 'name': 'log',
49
- 'type': 'system',
50
- 'id': None,
51
- 'engine': None,
52
- 'visible': True,
53
- 'deletable': False
54
- }]
41
+ result = [
42
+ {
43
+ "name": "information_schema",
44
+ "type": "system",
45
+ "id": None,
46
+ "engine": None,
47
+ "visible": True,
48
+ "deletable": False,
49
+ },
50
+ {"name": "log", "type": "system", "id": None, "engine": None, "visible": True, "deletable": False},
51
+ ]
55
52
  for x in projects:
56
- result.append({
57
- 'name': x.name,
58
- 'type': 'project',
59
- 'id': x.id,
60
- 'engine': None,
61
- 'visible': True,
62
- 'deletable': x.name.lower() != config.get('default_project')
63
- })
53
+ result.append(
54
+ {
55
+ "name": x.name,
56
+ "type": "project",
57
+ "id": x.id,
58
+ "engine": None,
59
+ "visible": True,
60
+ "deletable": x.name.lower() != config.get("default_project"),
61
+ }
62
+ )
64
63
  for key, value in integrations.items():
65
- db_type = value.get('type', 'data')
66
- if db_type != 'ml':
67
- result.append({
68
- 'name': key,
69
- 'type': value.get('type', 'data'),
70
- 'id': value.get('id'),
71
- 'engine': value.get('engine'),
72
- 'class_type': value.get('class_type'),
73
- 'connection_data': value.get('connection_data'),
74
- 'visible': True,
75
- 'deletable': value.get('permanent', False) is False
76
- })
64
+ db_type = value.get("type", "data")
65
+ if db_type != "ml":
66
+ result.append(
67
+ {
68
+ "name": key,
69
+ "type": value.get("type", "data"),
70
+ "id": value.get("id"),
71
+ "engine": value.get("engine"),
72
+ "class_type": value.get("class_type"),
73
+ "connection_data": value.get("connection_data"),
74
+ "visible": True,
75
+ "deletable": value.get("permanent", False) is False,
76
+ }
77
+ )
77
78
 
78
79
  if filter_type is not None:
79
- result = [x for x in result if x['type'] == filter_type]
80
+ result = [x for x in result if x["type"] == filter_type]
80
81
 
81
82
  return result
82
83
 
83
84
  def get_dict(self, filter_type: Optional[str] = None):
84
85
  return OrderedDict(
85
- (
86
- x['name'].lower(),
87
- {
88
- 'type': x['type'],
89
- 'engine': x['engine'],
90
- 'id': x['id']
91
- }
92
- )
86
+ (x["name"].lower(), {"type": x["type"], "engine": x["engine"], "id": x["id"]})
93
87
  for x in self.get_list(filter_type=filter_type)
94
88
  )
95
89
 
@@ -98,13 +92,8 @@ class DatabaseController:
98
92
 
99
93
  # TODO get directly from db?
100
94
  for rec in self.get_list():
101
- if rec['id'] == integration_id and rec['type'] == 'data':
102
- return {
103
- 'name': rec['name'],
104
- 'type': rec['type'],
105
- 'engine': rec['engine'],
106
- 'id': rec['id']
107
- }
95
+ if rec["id"] == integration_id and rec["type"] == "data":
96
+ return {"name": rec["name"], "type": rec["type"], "engine": rec["engine"], "id": rec["id"]}
108
97
 
109
98
  def exists(self, db_name: str) -> bool:
110
99
  return db_name.lower() in self.get_dict()
@@ -113,11 +102,46 @@ class DatabaseController:
113
102
  return self.project_controller.get(name=name)
114
103
 
115
104
  def get_system_db(self, name: str):
116
- if name == 'log':
105
+ if name == "log":
117
106
  return self.logs_db_controller
118
- elif name == 'information_schema':
107
+ elif name == "information_schema":
119
108
  from mindsdb.api.executor.controllers.session_controller import SessionController
109
+
120
110
  session = SessionController()
121
111
  return session.datahub
122
112
  else:
123
113
  raise Exception(f"Database '{name}' does not exists")
114
+
115
+ def update(self, name: str, data: dict):
116
+ """
117
+ Updates the database with the given name using the provided data.
118
+
119
+ Parameters:
120
+ name (str): The name of the database to update.
121
+ data (dict): The data to update the database with.
122
+
123
+ Raises:
124
+ EntityNotExistsError: If the database does not exist.
125
+ """
126
+ databases = self.get_dict()
127
+ name = name.lower()
128
+ if name not in databases:
129
+ raise EntityNotExistsError("Database does not exist.", name)
130
+
131
+ db_type = databases[name]["type"]
132
+ if db_type == "project":
133
+ # Only the name of the project can be updated.
134
+ if {"name"} != set(data):
135
+ raise ValueError("Only the 'name' field can be updated for projects.")
136
+ self.project_controller.update(name=name, new_name=str(data["name"]))
137
+ return
138
+
139
+ elif db_type == "data":
140
+ # Only the parameters (connection data) of the integration can be updated.
141
+ if {"parameters"} != set(data):
142
+ raise ValueError("Only the 'parameters' field can be updated for integrations.")
143
+ self.integration_controller.modify(name, data["parameters"])
144
+ return
145
+
146
+ else:
147
+ raise ValueError(f"Database with type '{db_type}' cannot be updated")