Skip to content

Instantly share code, notes, and snippets.

@Magnie
Created December 20, 2016 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Magnie/b1ee6b37cd94754946a22efacf3bba3e to your computer and use it in GitHub Desktop.
Save Magnie/b1ee6b37cd94754946a22efacf3bba3e to your computer and use it in GitHub Desktop.
from bson.objectid import ObjectId
from loaders.constants import *
"""
This simplifies managing an ever changing NoSQL database by versioning objects
and providing a simple way to update old version via update scripts.
The best way to use this is to create a new object and have it inherit from
ObjectData then provide the structure in the `versions` variable starting with
version 1. Then when you update the object structure, you can add in the
updated structure into the versions list, create an update script, add that to
the list of update scripts, and then you can pass data into the object and it
will update it to the latest version.
The ObjectManager is also there for convenience, but is designed specifically
for MongoDB. It isn't strictly necessary but can help simplify the process of
inserting, updating, and loading objects from the DB.
"""
class ObjectData(object):
versions = {
1: {
'_id': ObjectId,
'version': int,
},
}
version = 1
structure = versions[version]
raw_structure = dict((key, None) for key in structure)
def __init__(self, data={}):
self.version_scripts = {
1: self.update_1,
}
self.load_data(data)
def load_data(self, data):
# If the data has a version number, make sure it's the latest.
if 'version' in data and data['version'] and data['version'] != self.version:
self.data = self.update_latest(data)
# Otherwise assume it is the latest.
else:
self.data = self.raw_structure.copy()
self.data.update(data)
self.data['version'] = self.version
self.validate()
def validate(self):
validity = is_valid(self.data, self.structure)
if validity['errors'] or validity['warnings']:
print(validity)
if not validity:
raise InvalidData()
def update_latest(self, data):
if 'version' not in data:
raise InvalidData("A current version must be provided.")
version = data['version']
for v in xrange(version + 1, self.version + 1):
if v in self.version_scripts:
data = self.version_scripts[v](data)
return data
def update_1(self, input_data):
version = self.versions[1]
data = {}
for key in version:
data[key] = None
data.update(input_data)
return data
class ObjectManager(object):
database = None
object_data = ObjectData
structure = object_data.structure
def __init__(self):
if not self.database:
raise NoDatabaseSelected("No client was selected for Mongo.")
def get_by_id(self, object_id):
if type_valid(object_id, str):
data = self.collection.find_one({'_id': ObjectId(object_id)})
object_data = self.check_object(data)
return object_data
raise InvalidData("")
def get(self, query):
return self.collection.find(query)
def get_one(self, query):
result = self.collection.find_one(query)
return self.check_object(result)
def check_object(self, data):
"Checks if the object is up to date. If not, update the database."
object_data = self.object_data(data).data
# If they do not equal each other, then pass the fully updated data to
# update_object() to update the DB.
if data != object_data:
self.update_object(data['_id'], object_data)
return object_data
def create(self, data):
if len(is_valid(data, self.structure)['errors']):
raise InvalidData("")
new_object = self.object_data(data)
if '_id' in new_object.data and not new_object.data['_id']:
del new_object.data['_id']
return self.collection.insert_one(new_object.data)
def update_object(self, data):
if 'version' in data and data['version'] != self.object_data.version:
raise InvalidVersion("Object data is out of date.")
data = self.check_object(data)
if not is_valid(data, self.structure):
raise InvalidData()
object_id = data.get('_id')
if not object_id:
raise InvalidData("Can't update an object that doesn't exist!")
self.collection.update(
{'_id': object_id},
{'$set': data}
)
def delete_object(self, object_id):
result = self.collection.remove({
'_id': object_id,
})
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment