mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-04 03:13:49 +00:00
278 lines
8.9 KiB
Python
278 lines
8.9 KiB
Python
|
|
import datetime
|
|
|
|
import mongokit
|
|
from pymongo.objectid import ObjectId
|
|
|
|
from sailing.db.model.util import queryContent, createContent
|
|
from sailing.db import config
|
|
|
|
MARKER = object
|
|
|
|
class BaseDocument(mongokit.Document):
|
|
skip_validation = True
|
|
safe_mode = True
|
|
|
|
def _updateInternal(self, **kw):
|
|
kw['safe'] = self.safe_mode
|
|
if not hasattr(self, 'created') or \
|
|
not kw.get('created', None):
|
|
self['created'] = datetime.datetime.now()
|
|
|
|
if not hasattr(self, 'typename') or \
|
|
not kw.get('typename', None):
|
|
self['typename'] = self.__class__.__name__
|
|
|
|
return kw
|
|
|
|
def save(self, *args, **kw):
|
|
kw = self._updateInternal(**kw)
|
|
super(BaseDocument, self).save(*args, **kw)
|
|
|
|
def insert(self, *args, **kw):
|
|
kw = self._updateInternal(**kw)
|
|
super(BaseDocument, self).insert(*args, **kw)
|
|
|
|
def update(self, *args, **kw):
|
|
kw = self._updateInternal(**kw)
|
|
super(BaseDocument, self).update(*args, **kw)
|
|
|
|
class ModelBase(object):
|
|
|
|
@classmethod
|
|
def collectionName(cls):
|
|
return cls.linked_model._collection
|
|
|
|
@classmethod
|
|
def query(cls, uid, wrap=True):
|
|
uid = str(uid).strip()
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.get_from_id(ObjectId(uid))
|
|
|
|
if wrap is True:
|
|
if backend_instance:
|
|
if isinstance(backend_instance, list):
|
|
backend_instance = backend_instance[0]
|
|
return cls(backend_instance)
|
|
else:
|
|
return backend_instance
|
|
|
|
return None
|
|
|
|
@classmethod
|
|
def queryRaw(cls, input, limit=0, sortby='created', sortorder=config.DESCENDING):
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.find(input).limit(limit).sort(sortby, sortorder)
|
|
|
|
if backend_instance:
|
|
if backend_instance.count():
|
|
return [cls(ba) for ba in backend_instance]
|
|
|
|
return []
|
|
|
|
@classmethod
|
|
def queryBy(cls, limit=0, sortby='created', sortorder=config.DESCENDING, **fields):
|
|
assert isinstance(limit, int)
|
|
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
|
|
# update fields with typename
|
|
if not fields.get('typename', None):
|
|
fields['typename'] = cls.linked_model.__name__
|
|
|
|
# better would be to use fetch here because this includes structure but
|
|
# because we have one type per collection this doesn't matter
|
|
backend_instance = klass.find(fields).limit(limit).sort(sortby, direction=sortorder)
|
|
|
|
if backend_instance:
|
|
if backend_instance.count():
|
|
return [cls(ba) for ba in backend_instance]
|
|
|
|
return []
|
|
|
|
@classmethod
|
|
def queryByCount(cls, limit=0, sortby='created', sortorder=config.DESCENDING, **fields):
|
|
assert isinstance(limit, int)
|
|
|
|
# update fields with typename
|
|
if not fields.get('typename', None):
|
|
fields['typename'] = cls.linked_model.__name__
|
|
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.find(fields).limit(limit).sort(sortby, direction=sortorder)
|
|
return backend_instance.count()
|
|
|
|
@classmethod
|
|
def queryCount(cls, limit=0, sortby='created', sortorder=config.DESCENDING, **fields):
|
|
# update fields with typename
|
|
if not fields.get('typename', None):
|
|
fields['typename'] = cls.linked_model.__name__
|
|
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.find(fields).limit(limit).sort(sortby, direction=sortorder)
|
|
return backend_instance.count()
|
|
|
|
@classmethod
|
|
def queryRawCount(cls, input, limit=0, sortby='created', sortorder=config.DESCENDING):
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.find(input).limit(limit).sort(sortby, direction=sortorder)
|
|
return backend_instance.count()
|
|
|
|
@classmethod
|
|
def queryOneBy(cls, **fields):
|
|
# update fields with typename
|
|
if not fields.get('typename', None):
|
|
fields['typename'] = cls.linked_model.__name__
|
|
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
backend_instance = klass.find_one(fields)
|
|
|
|
if backend_instance:
|
|
return cls(backend_instance)
|
|
return None
|
|
|
|
@classmethod
|
|
def removeAllBy(cls, **fields):
|
|
if not fields.get('typename', None):
|
|
fields['typename'] = cls.linked_model.__name__
|
|
|
|
fields['atomic'] = True
|
|
klass = queryContent(cls.linked_model.__name__)
|
|
klass.collection.remove(**fields)
|
|
|
|
# assuming that we clean all objects
|
|
klass.collection.drop_indexes()
|
|
|
|
def __getstate__(self):
|
|
# we need to return a state where there is no connection
|
|
# to mongodb directly established - we just save the internal
|
|
# UID so to be able to rebuild the state later on
|
|
|
|
dc = self.__dict__.copy()
|
|
inst = dc['_instance']
|
|
|
|
if getattr(inst, '__dict__', None):
|
|
# we preserve the instance to avoid reloading it
|
|
# on unpickle - just preserving raw values
|
|
idc = {}; footprint = inst.structure
|
|
|
|
for k in footprint.keys():
|
|
# model changes can yield non-complete instances
|
|
if inst.has_key(k):
|
|
idc[str(k)] = inst[k]
|
|
|
|
idc['_id'] = dc['_instance']['_id']
|
|
|
|
del dc['_instance']
|
|
dc['_instance'] = idc
|
|
|
|
return dc
|
|
|
|
def __setstate__(self, state):
|
|
self.__dict__ = state
|
|
|
|
def __init__(self, instance = None, *args, **kw):
|
|
self._instance = instance
|
|
|
|
def __getattr__(self, key):
|
|
# instance attributes are held by backend
|
|
value = self.get(key, default=object)
|
|
|
|
# make sure to fall back to this class
|
|
if value is object:
|
|
return getattr(self.__class__, key)
|
|
|
|
return value
|
|
|
|
def get(self, key, default=None):
|
|
if key in self.__class__.linked_model.structure or key in ['_id', ]:
|
|
inst = self.__dict__['_instance']
|
|
if inst.has_key(key):
|
|
return inst.get(key)
|
|
return default
|
|
|
|
@property
|
|
def uid(self):
|
|
uid = getattr(self, '_id', None)
|
|
if uid:
|
|
return unicode(str(uid))
|
|
return None
|
|
|
|
def _backend(self):
|
|
return self.__class__.linked_model
|
|
|
|
def _instance_(self):
|
|
# use this method only for direct operations (crud)
|
|
inst = self.__dict__['_instance']
|
|
if inst:
|
|
# unpickling returns dict and not real mongokit instance
|
|
if not hasattr(inst, '__dict__'):
|
|
self.__dict__['_instance'] = self.query(inst['_id'], wrap=False)
|
|
return self.__dict__['_instance']
|
|
return inst
|
|
|
|
def getURL(self):
|
|
raise Exception, 'NotImplementedHere'
|
|
|
|
def getTitle(self):
|
|
raise Exception, 'NotImplementedHere'
|
|
|
|
def creationTime(self, pretty=False):
|
|
if pretty is True:
|
|
return pretty_date(self.created)
|
|
return self.created
|
|
|
|
def reload(self):
|
|
self._instance = self.query(self.uid, wrap=False)
|
|
|
|
def delete(self):
|
|
uid = self.uid
|
|
if not uid:
|
|
return False
|
|
|
|
self._instance_().delete()
|
|
return True
|
|
|
|
def update(self, dictionary=None, dosave=True):
|
|
klassname = self._backend().__name__
|
|
|
|
# make sure to make a difference between new and update
|
|
# new objects should always have empty uid field
|
|
if self.uid is None:
|
|
self._instance = createContent(klassname)
|
|
iis = self._instance_()
|
|
|
|
if hasattr(self, '_before_update'):
|
|
self._before_update(dictionary, creation=True)
|
|
|
|
# check that defaults are NOT set on backend
|
|
if hasattr(iis.__class__, 'default_values'):
|
|
if len(iis.__class__.default_values.keys())>0:
|
|
raise Exception, 'Implementation error: instance can not have defaults! Set defaults in model! Model: %s' % self._instance.__class__
|
|
|
|
# make sure to activate defaults
|
|
if hasattr(self.__class__, 'default_values'):
|
|
for dk,dv in self.__class__.default_values.items():
|
|
if dictionary is None \
|
|
or not dk in dictionary:
|
|
if callable(dv):
|
|
dv = dv()
|
|
|
|
iis[dk] = dv
|
|
else:
|
|
if self._instance_() is None:
|
|
self._instance = self.query(self.uid, wrap=False)
|
|
|
|
iis = self._instance_()
|
|
if hasattr(self, '_before_update'):
|
|
self._before_update(dictionary, creation=False)
|
|
|
|
if dictionary:
|
|
for k,v in dictionary.items():
|
|
iis[k] = v # need explicit set here
|
|
|
|
# save also works for update process
|
|
if dosave is True:
|
|
iis.save()
|
|
|