Coverage for mongodb_odm / connection.py: 100%
104 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 08:37 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-07 08:37 +0000
1import logging 1fabcde
2from typing import Any, Optional, Union, cast 1fabcde
4from mongodb_odm.exceptions import ConnectionError, InvalidAction, InvalidConnection 1fabcde
5from mongodb_odm.types import DICT_TYPE 1fabcde
6from mongodb_odm.utils._internal_models import Connection 1fabcde
7from pymongo import AsyncMongoClient, MongoClient 1fabcde
8from pymongo.asynchronous.database import AsyncDatabase 1fabcde
9from pymongo.database import Database 1fabcde
11logger = logging.getLogger(__name__) 1fabcde
13"""Store database connection related values in this variable""" 1abcde
14__connection_obj = Connection() 1fabcde
17def _get_connection_client(url: str, connection_kwargs: DICT_TYPE) -> MongoClient[Any]: 1fabcde
18 return MongoClient(url, **connection_kwargs) 1fabcde
21def _get_async_connection_client( 1fabcde
22 url: str, connection_kwargs: DICT_TYPE
23) -> AsyncMongoClient[Any]:
24 return AsyncMongoClient(url, **connection_kwargs) 1fabcde
27def connect( 1fabcde
28 url: str,
29 databases: Optional[set[str]] = None,
30 connection_kwargs: Optional[DICT_TYPE] = None,
31 async_is_enabled: bool = False,
32) -> Union[AsyncMongoClient[Any], MongoClient[Any]]:
33 """
34 This connect function should manage and store database connection config
35 that are passed by user.
37 url: string type, required
38 This should be a valid mongodb connection string with default database.
40 databases: set of strings, optional
41 values should be a set of strings that are assigned on define models.
42 The value is meant to validate that user is not trying to connect
43 to a database that is not defined in the models.
45 connection_kwargs: dict, optional
46 Additional connection parameters that can be passed to MongoClient or AsyncMongoClient.
48 async_is_enabled: bool, optional
49 If True then use AsyncMongoClient, otherwise use MongoClient.
50 Default is False.
51 """
52 global __connection_obj
54 if __connection_obj.client is not None: 1fabcde
55 """Log a warning if a user tries to connect multiple times.""" 1abcde
56 logger.warning("Already have an connection.") 1fabcde
57 return __connection_obj.client 1fabcde
59 __connection_obj = Connection() 1fabcde
61 if databases is None: 1fabcde
62 """Assign empty set as default value""" 1abcde
63 databases = set() 1fabcde
65 if not connection_kwargs: 1fabcde
66 connection_kwargs = {} 1fabcde
68 client: Union[AsyncMongoClient[Any], MongoClient[Any]]
69 if async_is_enabled: 1fabcde
70 client = _get_async_connection_client(url, connection_kwargs) 1fabcde
71 else:
72 client = _get_connection_client(url, connection_kwargs) 1fabcde
74 default_database = client.get_default_database().name 1fabcde
75 databases.add(default_database) 1fabcde
77 """Store the user configuration in the global variable to use later.""" 1abcde
78 __connection_obj.url = url 1fabcde
79 __connection_obj.databases = databases 1fabcde
80 __connection_obj.client = client 1fabcde
81 __connection_obj.async_is_enabled = async_is_enabled 1fabcde
82 __connection_obj.connection_kwargs = connection_kwargs 1fabcde
84 logger.info("Connection established successfully") 1fabcde
86 return __connection_obj.client 1fabcde
89def _disconnect_common() -> bool: 1fabcde
90 global __connection_obj
92 from mongodb_odm.models import _clear_cache 1fabcde
94 _clear_cache() 1fabcde
96 __connection_obj = Connection() # Reset the connection object 1fabcde
98 logger.info("Disconnect the db connection") 1fabcde
100 return True 1fabcde
103def disconnect(raise_error: bool = True) -> bool: 1fabcde
104 global __connection_obj
106 if __connection_obj.client is None: 1fabcde
107 logger.warning("No client connection found") 1fabcde
108 return _disconnect_common() 1fabcde
110 if isinstance(__connection_obj.client, AsyncMongoClient): 1fabcde
111 if not raise_error: 1fabcde
112 logger.warning( 1fabcde
113 "The client is configured as async. Use adisconnect() instead."
114 )
115 # We are not closing the async client expecting since this is a silent disconnect.
116 # Also it's not possible to call close() on an async client in a sync context.
117 __connection_obj.client = None 1fabcde
119 return _disconnect_common() 1fabcde
120 else:
121 raise InvalidAction( 1fabcde
122 "The client is configured as async. Use adisconnect() instead."
123 )
125 __connection_obj.client.close() 1fabcde
126 __connection_obj.client = None 1fabcde
128 return _disconnect_common() 1fabcde
131async def adisconnect(raise_error: bool = True) -> bool: 1fabcde
132 global __connection_obj
134 if __connection_obj.client is None: 1fabcde
135 logger.warning("No client connection found") 1fabcde
136 return _disconnect_common() 1fabcde
138 if isinstance(__connection_obj.client, MongoClient): 1fabcde
139 if not raise_error: 1fabcde
140 return disconnect() 1fabcde
141 else:
142 raise InvalidAction( 1fabcde
143 "The client is configured as sync. Use disconnect() instead."
144 )
146 await __connection_obj.client.close() 1fabcde
147 __connection_obj.client = None 1fabcde
149 return _disconnect_common() 1fabcde
152def get_client() -> Union[AsyncMongoClient[Any], MongoClient[Any]]: 1fabcde
153 """
154 Function should return MongoClient if url exists.
155 Otherwise raise ConnectionError error
156 """
157 global __connection_obj
159 if __connection_obj.client: 1fabcde
160 return __connection_obj.client 1fabcde
162 if __connection_obj.url is None: 1fabcde
163 raise ConnectionError("DB connection URL is not provided") 1fabcde
165 databases = __connection_obj.databases 1fabcde
166 connection_kwargs = __connection_obj.connection_kwargs 1fabcde
167 async_is_enabled = __connection_obj.async_is_enabled 1fabcde
169 return connect( 1fabcde
170 __connection_obj.url,
171 databases=databases,
172 connection_kwargs=connection_kwargs,
173 async_is_enabled=async_is_enabled,
174 )
177def db( 1fabcde
178 database: Optional[str] = None,
179 is_async_action: Optional[bool] = None,
180) -> Union[Database[Any], AsyncDatabase[Any]]:
181 global __connection_obj
183 if is_async_action is None: 1fabcde
184 is_async_action = __connection_obj.async_is_enabled 1fabcde
186 client = get_client() 1fabcde
188 if isinstance(client, MongoClient) and is_async_action is True: 1fabcde
189 raise InvalidAction("The client is not configured as async") 1fabcde
190 elif isinstance(client, AsyncMongoClient) and is_async_action is False: 1fabcde
191 raise InvalidAction("The client is not configured as sync") 1fabcde
193 if database: 1fabcde
194 if not __connection_obj.databases or database not in __connection_obj.databases: 1fabcde
195 """ 1abcde
196 Make sure valid database strings are passed
197 and avoid creating invalid databases by mistake
198 because mongodb creates databases on the fly.
199 """
200 raise InvalidConnection(f'Invalid database key was passed "{database}"') 1fabcde
202 return client[database] 1fabcde
203 else:
204 """ 1abcde
205 If database string was not passed then return default database
206 that is provided in connection url.
207 """
208 return client.get_database() 1fabcde
211def drop_database(database: Optional[str] = None) -> None: 1fabcde
212 collection = db(database, is_async_action=False) 1fabcde
214 collection.command("dropDatabase") 1fabcde
217async def adrop_database(database: Optional[str] = None) -> None: # noqa 1fabcde
218 collection = db(database, is_async_action=True) 1fabcde
220 collection = cast(AsyncDatabase[Any], collection) 1fabcde
222 await collection.command("dropDatabase") 1fabcde
225def is_async() -> bool: 1fabcde
226 global __connection_obj
228 if not __connection_obj.client: 1fabcde
229 raise ConnectionError("No connection established. Please connect first.") 1fabcde
231 return isinstance(__connection_obj.client, AsyncMongoClient) 1fabcde