Inspired by Mongokit, Simplemongo shares the same concept on designing the object oriented interface: using a predefined dict to restrict structure and value type of the document. ( mongoengine represents another genre, which use a rdbms way like django orm and that make simple things complicated ) But the validation mechanism of Simplemongo are formulated to be more reasonable and explicit. Following the philosophy of how MongoDB was made to be, it provides the most scalability under the premise of simplicity, let you think that you are still using pymongo and MongoDB, not some restrained orm with many rules you must follow.
The document is currently on development, feel free to check the code or test cases if you want to learn more.
import pymongo
from simplemongo import Document
# Simplemongo won't create the connection or choose the database for you,
# you must explicitly get you database object yourself
db = pymongo.Connection()['mydatabase']
class User(Document):
# Define the collection of User document class ('col' abbr 'collection')
col = db['user']
# Enable validation on writing the document
__validate__ = True
# Define the struct of the document
struct = {
'name': str,
'age': int,
'attributes': {
'vitality': float,
'armor': int,
'fortune': int,
},
}
user = User({
'name': 'reorx',
'age': 21,
'attributes': {
'vitality': 100.0,
'armor': 20,
'fortune': 15
}
})
# The document will be validated according to ``struct`` before writing to database
# An `_id` field will be added if not exist
user.save()
print user['_id']
# `user.identifier` returns {'_id': user['_id']} as the identifier of the document
# The arguments of Document's `find` method is just the same with `pymongo.Collection.find`
cursor = User.find(user.identifier)
# `cursor` support all the ways `pymongo.Cursor` instance can be operated,
# instead of dict, it returns the instance of `User` class
print cursor.next()
# `one` process a find query and return the only result of the query,
# if no result, it returns `None`, if get multiple results, it raise a `MultipleObjectsReturned` exception
fetched_user = User.one(user.identifier)
print fetched_user['_id'] == user['_id']
# The document data of user object can and only be changed by d[key] operation,
# dot notation (user.name) is not supported, dict should act as dict does
user['name'] = 'Reorx'
# `update` is just the dict update, it won't hit the database
user.update(age=22)
# `update_self` calls the `update` method of collection object,
# equals to: user.col.update(user.identifier, {'$set': {'attributes.armor': 30}})
user.update_self({'$set': {'attributes.armor': 30}})
# `update_changes` compares raw data with the changes we have made,
# then do a `update` operation on the original collection object,
# this line equals to:
# >>> user.col.update(user.identifier, {'$set': {'name': 'Reorx'}, '$inc': {'age': 1}})
user.update_changes()
# `remove` will remove a saved or fetched document from database,
# if the document is not written in database, an AssertErrro will be raised
user.remove()
class UserDict(StructuredDict):
struct = {
'name': str,
'age': int,
'attributes': {
'vitality': float,
'armor': int,
'fortune': int,
},
'slots': [str],
'skills': [
{
'name': str,
'level': int,
'damage': float,
'is_primary': bool,
'parents': [
{
'name': str,
'distance': int,
}
]
}
],
}
required_fields = [
'name', 'attributes.vitality', 'attributes.armor',
'skills', 'skills.name', 'skills.damage'
]
strict_fields = ['slots', 'skills.damage', 'skills.level']
The validation mechanism is based on three class attributes: struct
, required_fields
and strict_fields
struct
is considered the field-type checker, it only checks the type of fields in the document, ignore whether the structure of the document is matched.- A field defined in
struct
will only be checked when it exists in the document, if not exists,struct
check won't be triggered. - A field defined in
struct
is allowed to be ofNone
value. - A field not defined in
struct
will not be checked or handled, whatever value it is.
For fields defined in struct
there are two extra
attributes to configure validation conditions:
required_fields
A field in
required_fields
is required to exist in the document, if not, aKeyError
exception will be raised on validation.strict_fields
Whe a field in
strict_fields
exist in the docuement, its value must be strictly of the type defined in struct, that means, it could not be None unless the type is defined to beNone
So there are 4 situations for a field (defined in struct
firstly):
not required and not strict (marked
nr_ns
in test code)it can be:
- not exist
- exist and value is instance of type
- exist and value is None
required and not strict (marked
r_ns
in test code)it can be:
- exist and value is instance of type
- exist and value is None
not required and strict (marked
nr_s
in test code)it can be:
- not exist
- exist and value is instance of type
required and strict (marked
r_s
in test code)it can only be:
- exist and value is instance of type