database.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from collections import OrderedDict
  2. from . import CollectionInvalid
  3. from . import InvalidName
  4. from . import OperationFailure
  5. from .collection import Collection
  6. from mongomock import helpers
  7. class Database(object):
  8. def __init__(self, client, name):
  9. self.name = name
  10. self._client = client
  11. self._collections = {}
  12. def __getitem__(self, coll_name):
  13. return self.get_collection(coll_name)
  14. def __getattr__(self, attr):
  15. return self[attr]
  16. def __repr__(self):
  17. return "Database({0}, '{1}')".format(self._client, self.name)
  18. @property
  19. def client(self):
  20. return self._client
  21. def _get_created_collections(self):
  22. return [name for name, col in self._collections.items() if col._is_created()]
  23. def collection_names(self, include_system_collections=True):
  24. if include_system_collections:
  25. return list(self._get_created_collections())
  26. result = []
  27. for name in self._get_created_collections():
  28. if not name.startswith("system."):
  29. result.append(name)
  30. return result
  31. def get_collection(self, name, codec_options=None, read_preference=None,
  32. write_concern=None):
  33. collection = self._collections.get(name)
  34. if collection is None:
  35. collection = self._collections[name] = Collection(self, name)
  36. return collection
  37. def drop_collection(self, name_or_collection):
  38. try:
  39. if isinstance(name_or_collection, Collection):
  40. collection = next(c for c in self._collections.values() if c is name_or_collection)
  41. collection._documents = OrderedDict()
  42. collection._force_created = False
  43. collection.drop_indexes()
  44. else:
  45. if name_or_collection in self._collections:
  46. collection = self._collections.get(name_or_collection)
  47. if collection:
  48. collection._documents = OrderedDict()
  49. collection._force_created = False
  50. collection.drop_indexes()
  51. # EAFP paradigm
  52. # (http://en.m.wikipedia.org/wiki/Python_syntax_and_semantics)
  53. except Exception:
  54. pass
  55. def create_collection(self, name, **kwargs):
  56. if name in self.collection_names():
  57. raise CollectionInvalid("collection %s already exists" % name)
  58. if not name or '..' in name:
  59. raise InvalidName('collection names cannot be empty')
  60. if kwargs:
  61. raise NotImplementedError("Special options not supported")
  62. col = self[name]
  63. col._force_created = True
  64. return col
  65. def rename_collection(self, name, new_name, dropTarget=False):
  66. """Changes the name of an existing collection."""
  67. # These are the same checks that are done in pymongo.
  68. if not isinstance(new_name, helpers.basestring):
  69. raise TypeError("new_name must be an instance of basestring")
  70. if new_name[0] == "." or new_name[-1] == ".":
  71. raise InvalidName("collection names must not start or end with '.'")
  72. if "$" in new_name:
  73. raise InvalidName("collection names must not contain '$'")
  74. # Reference for server implementation:
  75. # https://docs.mongodb.com/manual/reference/command/renameCollection/
  76. if name not in self._collections:
  77. raise OperationFailure(
  78. 'The collection "{0}" does not exist.'.format(name), 10026)
  79. if new_name in self._collections:
  80. if dropTarget:
  81. self.drop_collection(new_name)
  82. else:
  83. raise OperationFailure(
  84. 'The target collection "{0}" already exists'.format(new_name),
  85. 10027)
  86. collection = self._collections.pop(name)
  87. collection.name = new_name
  88. self._collections[new_name] = collection
  89. def dereference(self, dbref):
  90. if not dbref.collection or not dbref.id:
  91. raise TypeError("cannot dereference a %s" % type(dbref))
  92. if dbref.database is not None and dbref.database != self.name:
  93. raise ValueError("trying to dereference a DBRef that points to "
  94. "another database (%r not %r)" % (dbref.database,
  95. self.__name))
  96. return self[dbref.collection].find_one({"_id": dbref.id})