MindsDB 25.8.3.0__py3-none-any.whl → 25.9.1.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 (94) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +2 -44
  3. mindsdb/api/a2a/__init__.py +52 -0
  4. mindsdb/api/a2a/agent.py +11 -12
  5. mindsdb/api/a2a/common/server/server.py +17 -36
  6. mindsdb/api/a2a/common/server/task_manager.py +14 -28
  7. mindsdb/api/a2a/task_manager.py +20 -21
  8. mindsdb/api/a2a/utils.py +1 -1
  9. mindsdb/api/common/middleware.py +106 -0
  10. mindsdb/api/http/initialize.py +13 -15
  11. mindsdb/api/http/namespaces/auth.py +6 -14
  12. mindsdb/api/http/namespaces/config.py +0 -2
  13. mindsdb/api/http/namespaces/default.py +74 -106
  14. mindsdb/api/http/start.py +25 -44
  15. mindsdb/api/litellm/start.py +11 -10
  16. mindsdb/api/mcp/__init__.py +165 -0
  17. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +33 -64
  18. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +86 -85
  19. mindsdb/integrations/handlers/crate_handler/crate_handler.py +3 -7
  20. mindsdb/integrations/handlers/derby_handler/derby_handler.py +32 -34
  21. mindsdb/integrations/handlers/documentdb_handler/requirements.txt +1 -0
  22. mindsdb/integrations/handlers/dummy_data_handler/dummy_data_handler.py +12 -13
  23. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +45 -44
  24. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +101 -95
  25. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +129 -129
  26. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +59 -43
  27. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +38 -39
  28. mindsdb/integrations/handlers/informix_handler/informix_handler.py +5 -18
  29. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +22 -28
  30. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +3 -7
  31. mindsdb/integrations/handlers/mongodb_handler/mongodb_handler.py +53 -67
  32. mindsdb/integrations/handlers/mongodb_handler/requirements.txt +1 -0
  33. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_ast.py +43 -68
  34. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_parser.py +17 -25
  35. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_query.py +10 -16
  36. mindsdb/integrations/handlers/mongodb_handler/utils/mongodb_render.py +43 -69
  37. mindsdb/integrations/libs/base.py +1 -1
  38. mindsdb/interfaces/agents/constants.py +1 -0
  39. mindsdb/interfaces/knowledge_base/controller.py +3 -1
  40. mindsdb/utilities/config.py +3 -155
  41. mindsdb/utilities/log.py +0 -25
  42. mindsdb/utilities/starters.py +0 -39
  43. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/METADATA +263 -261
  44. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/RECORD +47 -91
  45. mindsdb/api/a2a/__main__.py +0 -144
  46. mindsdb/api/a2a/run_a2a.py +0 -86
  47. mindsdb/api/common/check_auth.py +0 -42
  48. mindsdb/api/http/gunicorn_wrapper.py +0 -17
  49. mindsdb/api/mcp/start.py +0 -205
  50. mindsdb/api/mongo/__init__.py +0 -0
  51. mindsdb/api/mongo/classes/__init__.py +0 -5
  52. mindsdb/api/mongo/classes/query_sql.py +0 -19
  53. mindsdb/api/mongo/classes/responder.py +0 -45
  54. mindsdb/api/mongo/classes/responder_collection.py +0 -34
  55. mindsdb/api/mongo/classes/scram.py +0 -86
  56. mindsdb/api/mongo/classes/session.py +0 -23
  57. mindsdb/api/mongo/functions/__init__.py +0 -19
  58. mindsdb/api/mongo/responders/__init__.py +0 -73
  59. mindsdb/api/mongo/responders/add_shard.py +0 -13
  60. mindsdb/api/mongo/responders/aggregate.py +0 -90
  61. mindsdb/api/mongo/responders/buildinfo.py +0 -17
  62. mindsdb/api/mongo/responders/coll_stats.py +0 -63
  63. mindsdb/api/mongo/responders/company_id.py +0 -25
  64. mindsdb/api/mongo/responders/connection_status.py +0 -22
  65. mindsdb/api/mongo/responders/count.py +0 -21
  66. mindsdb/api/mongo/responders/db_stats.py +0 -32
  67. mindsdb/api/mongo/responders/delete.py +0 -105
  68. mindsdb/api/mongo/responders/describe.py +0 -23
  69. mindsdb/api/mongo/responders/end_sessions.py +0 -13
  70. mindsdb/api/mongo/responders/find.py +0 -175
  71. mindsdb/api/mongo/responders/get_cmd_line_opts.py +0 -18
  72. mindsdb/api/mongo/responders/get_free_monitoring_status.py +0 -14
  73. mindsdb/api/mongo/responders/get_parameter.py +0 -23
  74. mindsdb/api/mongo/responders/getlog.py +0 -14
  75. mindsdb/api/mongo/responders/host_info.py +0 -28
  76. mindsdb/api/mongo/responders/insert.py +0 -270
  77. mindsdb/api/mongo/responders/is_master.py +0 -20
  78. mindsdb/api/mongo/responders/is_master_lower.py +0 -13
  79. mindsdb/api/mongo/responders/list_collections.py +0 -55
  80. mindsdb/api/mongo/responders/list_databases.py +0 -37
  81. mindsdb/api/mongo/responders/list_indexes.py +0 -22
  82. mindsdb/api/mongo/responders/ping.py +0 -13
  83. mindsdb/api/mongo/responders/recv_chunk_start.py +0 -13
  84. mindsdb/api/mongo/responders/replsetgetstatus.py +0 -13
  85. mindsdb/api/mongo/responders/sasl_continue.py +0 -34
  86. mindsdb/api/mongo/responders/sasl_start.py +0 -33
  87. mindsdb/api/mongo/responders/update_range_deletions.py +0 -12
  88. mindsdb/api/mongo/responders/whatsmyuri.py +0 -18
  89. mindsdb/api/mongo/server.py +0 -388
  90. mindsdb/api/mongo/start.py +0 -15
  91. mindsdb/api/mongo/utilities/__init__.py +0 -0
  92. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/WHEEL +0 -0
  93. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/licenses/LICENSE +0 -0
  94. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.0.dist-info}/top_level.txt +0 -0
mindsdb/api/mcp/start.py DELETED
@@ -1,205 +0,0 @@
1
- import os
2
- from typing import Any
3
- from textwrap import dedent
4
- from contextlib import asynccontextmanager
5
- from collections.abc import AsyncIterator
6
- from dataclasses import dataclass
7
-
8
- import uvicorn
9
- import anyio
10
- from mcp.server.fastmcp import FastMCP
11
- from starlette.middleware.base import BaseHTTPMiddleware
12
- from starlette.requests import Request
13
- from starlette.responses import Response
14
-
15
- from mindsdb.api.mysql.mysql_proxy.classes.fake_mysql_proxy import FakeMysqlProxy
16
- from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE as SQL_RESPONSE_TYPE
17
- from mindsdb.utilities import log
18
- from mindsdb.utilities.log import get_uvicorn_logging_config
19
- from mindsdb.utilities.config import Config
20
- from mindsdb.interfaces.storage import db
21
-
22
- logger = log.getLogger(__name__)
23
-
24
-
25
- @dataclass
26
- class AppContext:
27
- db: Any
28
-
29
-
30
- @asynccontextmanager
31
- async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
32
- """Manage application lifecycle with type-safe context"""
33
- # Initialize on startup
34
- db.init()
35
- try:
36
- yield AppContext(db=db)
37
- finally:
38
- # TODO: We need better way to handle this in storage/db.py
39
- pass
40
-
41
-
42
- # Configure server with lifespan
43
- mcp = FastMCP(
44
- "MindsDB",
45
- lifespan=app_lifespan,
46
- dependencies=["mindsdb"], # Add any additional dependencies
47
- )
48
- # MCP Queries
49
- LISTING_QUERY = "SHOW DATABASES"
50
-
51
-
52
- query_tool_description = dedent("""\
53
- Executes a SQL query against MindsDB.
54
-
55
- A database must be specified either in the `context` parameter or directly in the query string (e.g., `SELECT * FROM my_database.my_table`). Queries like `SELECT * FROM my_table` will fail without a `context`.
56
-
57
- Args:
58
- query (str): The SQL query to execute.
59
- context (dict, optional): The default database context. For example, `{"db": "my_postgres"}`.
60
-
61
- Returns:
62
- A dictionary describing the result.
63
- - For a successful query with no data to return (e.g., an `UPDATE` statement), the response is `{"type": "ok"}`.
64
- - If the query returns tabular data, the response is a dictionary containing `data` (a list of rows) and `column_names` (a list of column names). For example: `{"type": "table", "data": [[1, "a"], [2, "b"]], "column_names": ["column_a", "column_b"]}`.
65
- - In case of an error, a response is `{"type": "error", "error_message": "the error message"}`.
66
- """)
67
-
68
-
69
- @mcp.tool(name="query", description=query_tool_description)
70
- def query(query: str, context: dict | None = None) -> dict[str, Any]:
71
- """Execute a SQL query against MindsDB
72
-
73
- Args:
74
- query: The SQL query to execute
75
- context: Optional context parameters for the query
76
-
77
- Returns:
78
- Dict containing the query results or error information
79
- """
80
-
81
- if context is None:
82
- context = {}
83
-
84
- logger.debug(f"Incoming MCP query: {query}")
85
-
86
- mysql_proxy = FakeMysqlProxy()
87
- mysql_proxy.set_context(context)
88
-
89
- try:
90
- result = mysql_proxy.process_query(query)
91
-
92
- if result.type == SQL_RESPONSE_TYPE.OK:
93
- return {"type": SQL_RESPONSE_TYPE.OK}
94
-
95
- if result.type == SQL_RESPONSE_TYPE.TABLE:
96
- return {
97
- "type": SQL_RESPONSE_TYPE.TABLE,
98
- "data": result.result_set.to_lists(json_types=True),
99
- "column_names": [column.alias or column.name for column in result.result_set.columns],
100
- }
101
- else:
102
- return {"type": SQL_RESPONSE_TYPE.ERROR, "error_code": 0, "error_message": "Unknown response type"}
103
-
104
- except Exception as e:
105
- logger.error(f"Error processing query: {str(e)}")
106
- return {"type": SQL_RESPONSE_TYPE.ERROR, "error_code": 0, "error_message": str(e)}
107
-
108
-
109
- list_databases_tool_description = (
110
- "Returns a list of all database connections currently available in MindsDB. "
111
- + "The tool takes no parameters and responds with a list of database names, "
112
- + 'for example: ["my_postgres", "my_mysql", "test_db"].'
113
- )
114
-
115
-
116
- @mcp.tool(name="list_databases", description=list_databases_tool_description)
117
- def list_databases() -> list[str]:
118
- """
119
- List all databases in MindsDB
120
-
121
- Returns:
122
- list[str]: list of databases
123
- """
124
-
125
- mysql_proxy = FakeMysqlProxy()
126
-
127
- try:
128
- result = mysql_proxy.process_query(LISTING_QUERY)
129
- if result.type == SQL_RESPONSE_TYPE.ERROR:
130
- return {
131
- "type": "error",
132
- "error_code": result.error_code,
133
- "error_message": result.error_message,
134
- }
135
-
136
- elif result.type == SQL_RESPONSE_TYPE.OK:
137
- return {"type": "ok"}
138
-
139
- elif result.type == SQL_RESPONSE_TYPE.TABLE:
140
- data = result.result_set.to_lists(json_types=True)
141
- data = [val[0] for val in data]
142
- return data
143
-
144
- except Exception as e:
145
- return {
146
- "type": "error",
147
- "error_code": 0,
148
- "error_message": str(e),
149
- }
150
-
151
-
152
- class CustomAuthMiddleware(BaseHTTPMiddleware):
153
- """Custom middleware to handle authentication basing on header 'Authorization'"""
154
-
155
- async def dispatch(self, request: Request, call_next):
156
- mcp_access_token = os.environ.get("MINDSDB_MCP_ACCESS_TOKEN")
157
- if mcp_access_token is not None:
158
- auth_token = request.headers.get("Authorization", "").partition("Bearer ")[-1]
159
- if mcp_access_token != auth_token:
160
- return Response(status_code=401, content="Unauthorized", media_type="text/plain")
161
-
162
- response = await call_next(request)
163
-
164
- return response
165
-
166
-
167
- async def run_sse_async() -> None:
168
- """Run the server using SSE transport."""
169
- starlette_app = mcp.sse_app()
170
- starlette_app.add_middleware(CustomAuthMiddleware)
171
-
172
- config = uvicorn.Config(
173
- starlette_app,
174
- host=mcp.settings.host,
175
- port=mcp.settings.port,
176
- log_level=mcp.settings.log_level.lower(),
177
- log_config=get_uvicorn_logging_config("uvicorn_mcp"),
178
- )
179
- server = uvicorn.Server(config)
180
- await server.serve()
181
-
182
-
183
- def start(*args, **kwargs):
184
- """Start the MCP server
185
- Args:
186
- host (str): Host to bind to
187
- port (int): Port to listen on
188
- """
189
- config = Config()
190
- port = int(config["api"].get("mcp", {}).get("port", 47337))
191
- host = config["api"].get("mcp", {}).get("host", "127.0.0.1")
192
-
193
- logger.info(f"Starting MCP server on {host}:{port}")
194
- mcp.settings.host = host
195
- mcp.settings.port = port
196
-
197
- try:
198
- anyio.run(run_sse_async)
199
- except Exception as e:
200
- logger.error(f"Error starting MCP server: {str(e)}")
201
- raise
202
-
203
-
204
- if __name__ == "__main__":
205
- start()
File without changes
@@ -1,5 +0,0 @@
1
- from .responder_collection import RespondersCollection
2
- from .responder import Responder
3
- from .session import Session
4
-
5
- __all__ = ['RespondersCollection', 'Responder', 'Session']
@@ -1,19 +0,0 @@
1
- from mindsdb.api.executor.controllers import SessionController
2
- from mindsdb.api.executor.command_executor import ExecuteCommands
3
- from mindsdb.utilities.config import config
4
-
5
-
6
- def run_sql_command(request_env, ast_query):
7
- sql_session = SessionController()
8
- sql_session.database = request_env.get('database', config.get('default_project'))
9
-
10
- command_executor = ExecuteCommands(sql_session)
11
- ret = command_executor.execute_command(ast_query)
12
- if ret.error_code is not None:
13
- raise Exception(ret.error_message)
14
-
15
- if ret.data is None:
16
- # return no data
17
- return []
18
-
19
- return list(ret.data.get_records())
@@ -1,45 +0,0 @@
1
- class Responder():
2
- def __init__(self, when=None, result=None):
3
- if when is not None:
4
- self.when = when
5
- if result is not None:
6
- self.result = result
7
- if not hasattr(self, 'when') or (not isinstance(self.when, dict) and not callable(self.when)):
8
- raise ValueError("Responder attr 'when' must be dict or function.")
9
- if not hasattr(self, 'result') or (not isinstance(self.result, dict) and not callable(self.result)):
10
- raise ValueError("Responder attr 'result' must be dict or function.")
11
-
12
- def match(self, query):
13
- """ check, if this 'responder' can be used to answer or current request
14
-
15
- query (dict): request document
16
-
17
- return bool
18
- """
19
- if isinstance(self.when, dict):
20
- for key, value in self.when.items():
21
- if key not in query:
22
- return False
23
- if callable(value):
24
- if not value(query[key]):
25
- return False
26
- elif value != query[key]:
27
- return False
28
- return True
29
- else:
30
- return self.when(query)
31
-
32
- def handle(self, query, args, env, session):
33
- """ making answer based on params:
34
-
35
- query (dict): document(s) from request
36
- args (dict): all other significant information from request: flags, collection name, rows to return, etc
37
- env (dict): config, model_controller instance, and other mindsdb related stuff
38
- session (object): current session
39
-
40
- returns documents as dict or list of dicts
41
- """
42
- if isinstance(self.result, dict):
43
- return self.result
44
- else:
45
- return self.result(query, args, env, session)
@@ -1,34 +0,0 @@
1
- from .responder import Responder
2
- from mindsdb.utilities import log
3
-
4
- logger = log.getLogger(__name__)
5
-
6
-
7
- class RespondersCollection():
8
- def __init__(self):
9
- self.responders = []
10
-
11
- def find_match(self, query):
12
- for r in self.responders:
13
- if r.match(query):
14
- return r
15
-
16
- msg = f'Is not responder for query: {query}'
17
-
18
- class ErrorResponder(Responder):
19
- when = {}
20
-
21
- result = {
22
- "ok": 0.0,
23
- "errmsg": msg,
24
- "code": 59,
25
- "codeName": "CommandNotFound"
26
- }
27
-
28
- logger.error(msg)
29
- return ErrorResponder()
30
-
31
- def add(self, when, result):
32
- self.responders.append(
33
- Responder(when, result)
34
- )
@@ -1,86 +0,0 @@
1
- # https://stackoverflow.com/questions/29298346/xmpp-sasl-scram-sha1-authentication
2
- # https://tools.ietf.org/html/rfc5802
3
- # https://tools.ietf.org/html/rfc7677
4
-
5
- import base64
6
- import hashlib
7
- import hmac
8
- import os
9
-
10
- from pymongo.auth import _password_digest, _xor, saslprep
11
-
12
-
13
- class Scram():
14
- ''' implementation of server-side SCRAM-SHA-1 and SCRAM-SHA-256 auth for mongodb
15
- '''
16
-
17
- def __init__(self, method='sha1', get_salted_password=None):
18
- self.get_salted_password = get_salted_password
19
- self.snonce = base64.b64encode(os.urandom(24)).decode()
20
- self.iterations = 4096
21
- self.messages = []
22
-
23
- if method == 'sha1':
24
- self.method_str = 'sha1'
25
- self.method_func = hashlib.sha1
26
- self.salt = base64.b64encode(os.urandom(16))
27
- elif method == 'sha256':
28
- self.method_str = 'sha256'
29
- self.method_func = hashlib.sha256
30
- self.salt = base64.b64encode(os.urandom(28))
31
-
32
- def process_client_first_message(self, payload):
33
- payload = payload[3:]
34
- payload_parts = self._split_payload(payload)
35
- self.client_user = payload_parts['n']
36
-
37
- if self.get_salted_password is not None:
38
- salt_bytes, self.salted_password = self.get_salted_password(self.client_user, self.method_str)
39
- self.salt = base64.b64encode(salt_bytes)
40
- else:
41
- self.salted_password = self.salt_password()
42
-
43
- self.unonce = payload_parts['r']
44
- self.messages.append(payload)
45
-
46
- responce_msg = f"r={self.unonce}{self.snonce},s={self.salt.decode()},i={self.iterations}"
47
- self.messages.append(responce_msg)
48
- return responce_msg
49
-
50
- def process_client_second_message(self, payload):
51
- self.messages.append(payload[:payload.rfind(',p=')]) # without 'p' part
52
-
53
- messages = ','.join(self.messages)
54
- server_key = self._hmac(self.salted_password, b'Server Key')
55
- server_signature = self._hmac(server_key, messages.encode('utf-8'))
56
-
57
- client_key = self._hmac(self.salted_password, b'Client Key')
58
- stored_key = self.method_func(client_key).digest()
59
- client_signature = self._hmac(stored_key, messages.encode('utf-8'))
60
- expected_client_proof = base64.b64encode(_xor(client_key, client_signature)).decode()
61
-
62
- income_client_proof = payload[payload.rfind(',p=') + 3:]
63
-
64
- if expected_client_proof != income_client_proof:
65
- raise Exception('wrong password')
66
-
67
- return f'v={base64.b64encode(server_signature).decode()}'
68
-
69
- def _hmac(self, key, msg):
70
- return hmac.new(key, msg, digestmod=self.method_func).digest()
71
-
72
- def salt_password(self, user, password):
73
- if self.method_str == 'sha1':
74
- password = _password_digest(user, password).encode("utf-8")
75
- elif self.method_str == 'sha256':
76
- password = saslprep(password).encode("utf-8")
77
-
78
- return hashlib.pbkdf2_hmac(
79
- self.method_str, password, base64.b64decode(self.salt), self.iterations
80
- )
81
-
82
- def _split_payload(self, payload):
83
- parts = {}
84
- for part in [x for x in payload.split(',') if len(x) > 0]:
85
- parts[part[0]] = part[2:]
86
- return parts
@@ -1,23 +0,0 @@
1
- import base64
2
-
3
- from mindsdb.api.mongo.classes.scram import Scram
4
-
5
-
6
- class Session():
7
- def __init__(self, server_mindsdb_env):
8
- self.config = server_mindsdb_env['config']
9
- self.mindsdb_env = {'company_id': None}
10
- self.mindsdb_env.update(server_mindsdb_env)
11
-
12
- def init_scram(self, method):
13
- self.scram = Scram(method=method, get_salted_password=self.get_salted_password)
14
-
15
- def get_salted_password(self, username, method=None):
16
- real_user = self.config['auth'].get('username', '')
17
- password = self.config['auth'].get('password', '')
18
- if username != real_user:
19
- raise Exception(f'Wrong username {username}')
20
-
21
- salted_password = self.scram.salt_password(real_user, password)
22
-
23
- return base64.b64decode(self.scram.salt), salted_password
@@ -1,19 +0,0 @@
1
- import bson
2
-
3
-
4
- def is_true(val):
5
- return bool(val) is True
6
-
7
-
8
- def is_false(val):
9
- return bool(val) is False
10
-
11
-
12
- def int_to_objectid(n):
13
- s = str(n)
14
- s = '0' * (24 - len(s)) + s
15
- return bson.ObjectId(s)
16
-
17
-
18
- def objectid_to_int(obj):
19
- return int(str(obj))
@@ -1,73 +0,0 @@
1
- from .whatsmyuri import responder as responder_whatsmyuri
2
- from .buildinfo import responder as responder_buildinfo
3
- from .is_master import responder as responder_is_master
4
- from .is_master_lower import responder as responder_is_master_lower
5
- from .replsetgetstatus import responder as responder_replsetgetstatus
6
- from .getlog import responder as responder_getlog
7
- from .add_shard import responder as responder_add_shard
8
- from .update_range_deletions import responder as responder_update_range_deletions
9
- from .recv_chunk_start import responder as responder_recv_chunk_start
10
- from .connection_status import responder as responder_connection_status
11
- from .get_cmd_line_opts import responder as responder_get_cmd_line_opts
12
- from .host_info import responder as responder_host_info
13
- from .db_stats import responder as responder_db_stats
14
- from .coll_stats import responder as responder_coll_stats
15
- from .count import responder as responder_count
16
- from .aggregate import responder as responder_aggregate
17
- from .get_free_monitoring_status import responder as responder_get_free_monitoring_status
18
- from .end_sessions import responder as responder_end_sessions
19
- from .ping import responder as responder_ping
20
- from .get_parameter import responder as responder_get_parameter
21
-
22
- from .list_indexes import responder as responder_list_indexes
23
- from .list_collections import responder as responder_list_collections
24
- from .list_databases import responder as responder_list_databases
25
-
26
- from .find import responder as responder_find
27
- from .insert import responder as responder_insert
28
- from .delete import responder as responder_delete
29
- from .describe import responder as responder_describe
30
-
31
- from .sasl_start import responder as sasl_start
32
- from .sasl_continue import responder as sasl_continue
33
-
34
- from .company_id import responder as responder_company_id
35
-
36
-
37
- responders = [
38
- # service queries
39
- responder_whatsmyuri,
40
- responder_buildinfo,
41
- responder_is_master,
42
- responder_is_master_lower,
43
- responder_replsetgetstatus,
44
- responder_getlog,
45
- responder_add_shard, # 4.4
46
- responder_update_range_deletions, # 4.4
47
- responder_recv_chunk_start, # 4.4
48
- responder_connection_status,
49
- responder_get_cmd_line_opts,
50
- responder_host_info,
51
- responder_db_stats,
52
- responder_coll_stats,
53
- responder_count,
54
- responder_aggregate,
55
- responder_get_free_monitoring_status,
56
- responder_end_sessions,
57
- responder_ping,
58
- responder_get_parameter,
59
-
60
- # user queries
61
- responder_list_indexes,
62
- responder_list_collections,
63
- responder_list_databases,
64
- responder_find,
65
- responder_insert,
66
- responder_delete,
67
- responder_describe,
68
- # auth
69
- sasl_start,
70
- sasl_continue,
71
- # cloud
72
- responder_company_id
73
- ]
@@ -1,13 +0,0 @@
1
- from mindsdb.api.mongo.classes import Responder
2
- import mindsdb.api.mongo.functions as helpers
3
-
4
-
5
- class Responce(Responder):
6
- when = {'_addShard': helpers.is_true}
7
-
8
- result = {
9
- "ok": 1
10
- }
11
-
12
-
13
- responder = Responce()
@@ -1,90 +0,0 @@
1
- from bson.int64 import Int64
2
-
3
- from mindsdb_sql_parser.ast import Identifier, Insert, CreateTable
4
-
5
- from mindsdb.api.mongo.classes import Responder
6
- import mindsdb.api.mongo.functions as helpers
7
- from mindsdb.api.mongo.responders.find import find_to_ast
8
- from mindsdb.api.mongo.classes.query_sql import run_sql_command
9
- from mindsdb.utilities.config import config
10
-
11
-
12
- def aggregate_to_ast(query, database):
13
- collection = query['aggregate']
14
-
15
- save_table = None
16
- is_append = False
17
- first_step = query['pipeline'][0]
18
- if '$match' in first_step:
19
- # convert to find
20
- find_query = {
21
- 'find': collection,
22
- 'filter': first_step['$match'],
23
- }
24
- for step in query['pipeline'][1:]:
25
- if '$project' in step:
26
- find_query['projection'] = step['$project']
27
- if '$sort' in step:
28
- find_query['sort'] = step['$sort']
29
- if '$skip' in step:
30
- find_query['skip'] = step['$skip']
31
- if '$limit' in step:
32
- find_query['limit'] = step['$limit']
33
-
34
- if '$out' in step:
35
- target = step['$out']
36
- if isinstance(target, str):
37
- save_table = Identifier(target)
38
- else:
39
- save_table = Identifier(parts=[target['db'], target['coll']])
40
- if target.get('append'):
41
- is_append = True
42
-
43
- # TODO implement group
44
- ast_query = find_to_ast(find_query, database)
45
- if save_table is not None:
46
- if is_append:
47
- ast_query = Insert(save_table, from_select=ast_query)
48
- else:
49
- ast_query = CreateTable(save_table, from_select=ast_query, is_replace=True)
50
-
51
- else:
52
- raise NotImplementedError
53
-
54
- return ast_query
55
-
56
-
57
- class Responce(Responder):
58
- when = {'aggregate': helpers.is_true}
59
-
60
- def result(self, query, request_env, mindsdb_env, session):
61
- db = query['$db']
62
- collection = query['aggregate']
63
-
64
- first_step = query['pipeline'][0]
65
- if '$match' in first_step:
66
- ast_query = aggregate_to_ast(query, request_env.get('database', config.get('default_project')))
67
-
68
- data = run_sql_command(request_env, ast_query)
69
-
70
- elif '$collStats' in first_step:
71
- raise ValueError(
72
- "To describe model use:"
73
- " db.runCommand({describe: 'model_name.attribute'})"
74
- )
75
-
76
- else:
77
- raise NotImplementedError
78
-
79
- cursor = {
80
- 'id': Int64(0),
81
- 'ns': f"{db}.$cmd.{collection}",
82
- 'firstBatch': data
83
- }
84
- return {
85
- 'cursor': cursor,
86
- 'ok': 1
87
- }
88
-
89
-
90
- responder = Responce()
@@ -1,17 +0,0 @@
1
- from mindsdb.api.mongo.classes import Responder
2
-
3
-
4
- class Responce(Responder):
5
- def when(self, query):
6
- return (
7
- 'buildinfo' in query or 'buildInfo' in query
8
- )
9
-
10
- result = {
11
- 'version': '3.6.8',
12
- 'versionArray': [3, 6, 8, 0],
13
- 'ok': 1
14
- }
15
-
16
-
17
- responder = Responce()