-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Extract ConnectionManager to handle setup connection before using it … #1457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
from collections import defaultdict | ||
|
||
from mongoengine.connection import get_connection, get_db | ||
|
||
__all__ = ['InvalidCollectionError', 'connection_manager'] | ||
|
||
|
||
class InvalidCollectionError(Exception): | ||
pass | ||
|
||
|
||
class ConnectionManager(object): | ||
connections_registry = defaultdict(dict) | ||
|
||
def get_and_setup(self, doc_cls, alias=None, collection_name=None): | ||
if alias is None: | ||
alias = doc_cls._get_db_alias() | ||
|
||
if collection_name is None: | ||
collection_name = doc_cls._get_collection_name() | ||
|
||
_collection = self.connections_registry[alias].get(collection_name) | ||
if not _collection: | ||
_collection = self.get_collection(doc_cls, alias, collection_name) | ||
if doc_cls._meta.get('auto_create_index', True): | ||
doc_cls.ensure_indexes(_collection) | ||
self.connections_registry[alias][collection_name] = _collection | ||
return self.connections_registry[alias][collection_name] | ||
|
||
@classmethod | ||
def _get_db(cls, alias): | ||
"""Some Model using other db_alias""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The docstring here is pretty confusing. What is "Some Model"? Why is it using "other db_alias"? Why do we need a private method that only proxies a call to a public |
||
return get_db(alias) | ||
|
||
@classmethod | ||
def get_collection(cls, doc_cls, alias=None, collection_name=None): | ||
"""Returns the collection for the document.""" | ||
|
||
if alias is None: | ||
alias = doc_cls._get_db_alias() | ||
|
||
if collection_name is None: | ||
collection_name = doc_cls._get_collection_name() | ||
|
||
db = cls._get_db(alias=alias) | ||
|
||
# Create collection as a capped collection if specified | ||
if doc_cls._meta.get('max_size') or doc_cls._meta.get('max_documents'): | ||
# Get max document limit and max byte size from meta | ||
max_size = doc_cls._meta.get('max_size') or 10 * 2 ** 20 # 10MB default | ||
max_documents = doc_cls._meta.get('max_documents') | ||
# Round up to next 256 bytes as MongoDB would do it to avoid exception | ||
if max_size % 256: | ||
max_size = (max_size // 256 + 1) * 256 | ||
|
||
if collection_name in db.collection_names(): | ||
_collection = db[collection_name] | ||
# The collection already exists, check if its capped | ||
# options match the specified capped options | ||
options = _collection.options() | ||
if ( | ||
options.get('max') != max_documents or | ||
options.get('size') != max_size | ||
): | ||
msg = (('Cannot create collection "%s" as a capped ' | ||
'collection as it already exists') | ||
% _collection) | ||
raise InvalidCollectionError(msg) | ||
else: | ||
# Create the collection as a capped collection | ||
opts = {'capped': True, 'size': max_size} | ||
if max_documents: | ||
opts['max'] = max_documents | ||
_collection = db.create_collection( | ||
collection_name, **opts | ||
) | ||
else: | ||
_collection = db[collection_name] | ||
return _collection | ||
|
||
def drop_collection(self, doc_cls, alias, collection_name): | ||
if alias is None: | ||
alias = doc_cls._get_db_alias() | ||
|
||
if collection_name is None: | ||
collection_name = doc_cls._get_collection_name() | ||
|
||
if not collection_name: | ||
from mongoengine.queryset import OperationError | ||
raise OperationError('Document %s has no collection defined ' | ||
'(is it abstract ?)' % doc_cls) | ||
|
||
self.connections_registry[alias][collection_name] = None | ||
db = self._get_db(alias=alias) | ||
db.drop_collection(collection_name) | ||
|
||
def drop_database(self, doc_cls, alias=None): | ||
if alias is None: | ||
alias = doc_cls._get_db_alias() | ||
|
||
self.connections_registry[alias] = {} | ||
db = self._get_db(alias=alias) | ||
conn = get_connection(alias) | ||
conn.drop_database(db) | ||
|
||
def reset(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could use a docstring, too. Additionally, should this method perform any cleanup of the connections before dropping references to them? Will that leave lingering unclosed connections to the database? |
||
self.connections_registry = defaultdict(dict) | ||
|
||
|
||
connection_manager = ConnectionManager() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use a docstring, especially as a public method. What it doesn, when it should be used, etc.