1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2025-10-31 19:49:02 +01:00

Bugfixes in backref handling in mongodb datasrouce refs #131

Now backref seems to work at creation of a Person linked with a text the Person UID is appended to Text.linked_persons
This commit is contained in:
Yann 2016-09-07 12:32:09 +02:00
commit e602e009ad
2 changed files with 67 additions and 71 deletions

View file

@ -477,6 +477,9 @@ class LeInsertQuery(LeQuery):
_data_check_args = { 'complete': True, 'allow_internal': False } _data_check_args = { 'complete': True, 'allow_internal': False }
def __init__(self, target_class): def __init__(self, target_class):
if target_class.is_abstract():
raise LeApiQueryError("Trying to create an insert query on an \
abstract LeObject : %s" % target_class )
super().__init__(target_class) super().__init__(target_class)
## @brief Implements an insert query operation, with only one insertion ## @brief Implements an insert query operation, with only one insertion

View file

@ -199,9 +199,13 @@ class MongoDbDatasource(object):
#@return int : number of deleted records #@return int : number of deleted records
def delete(self, target, filters, relational_filters): def delete(self, target, filters, relational_filters):
if target.is_abstract(): if target.is_abstract():
logger.debug("Delete called on %s filtered by (%s,%s). Target is \
abstract, preparing reccursiv calls" % (target, filters, relational_filters))
#Deletion with abstract LeObject as target (reccursiv calls) #Deletion with abstract LeObject as target (reccursiv calls)
return self.__act_on_abstract(target, filters, return self.__act_on_abstract(target, filters,
relational_filters, self.delete) relational_filters, self.delete)
logger.debug("Delete called on %s filtered by (%s,%s)." % (
target, filters, relational_filters))
#Non abstract beahavior #Non abstract beahavior
mongo_filters = self.__process_filters( mongo_filters = self.__process_filters(
target, filters, relational_filters) target, filters, relational_filters)
@ -218,7 +222,7 @@ class MongoDbDatasource(object):
#@param upd_datas dict : datas to update (new values) #@param upd_datas dict : datas to update (new values)
#@return int : Number of updated records #@return int : Number of updated records
def update(self, target, filters, relational_filters, upd_datas): def update(self, target, filters, relational_filters, upd_datas):
res = self.__upodate_no_backref(target, filters, relational_filters, res = self.__update_no_backref(target, filters, relational_filters,
upd_datas) upd_datas)
self.__update_backref_filtered(target, filters, relational_filters, self.__update_backref_filtered(target, filters, relational_filters,
upd_datas) upd_datas)
@ -229,6 +233,8 @@ class MongoDbDatasource(object):
#@see update() #@see update()
def __update_no_backref(self, target, filters, relational_filters, def __update_no_backref(self, target, filters, relational_filters,
upd_datas): upd_datas):
logger.debug("Update called on %s filtered by (%s,%s) with datas \
%s" % (target, filters, relational_filters, upd_datas))
if target.is_abstract(): if target.is_abstract():
#Update using abstract LeObject as target (reccursiv calls) #Update using abstract LeObject as target (reccursiv calls)
return self.__act_on_abstract(target, filters, return self.__act_on_abstract(target, filters,
@ -236,7 +242,8 @@ class MongoDbDatasource(object):
#Non abstract beahavior #Non abstract beahavior
mongo_filters = self.__process_filters( mongo_filters = self.__process_filters(
target, filters, relational_filters) target, filters, relational_filters)
res = self.__collection(target).update(mongo_filters, upd_datas) mongo_arg = {'$set': upd_datas }
res = self.__collection(target).update(mongo_filters, mongo_arg)
return res['n'] return res['n']
@ -246,8 +253,12 @@ class MongoDbDatasource(object):
# @param new_datas dict : datas to insert # @param new_datas dict : datas to insert
# @return the inserted uid # @return the inserted uid
def insert(self, target, new_datas): def insert(self, target, new_datas):
logger.debug("Insert called on %s with datas : %s"% (
target, new_datas))
res = self.__collection(target).insert(new_datas) res = self.__collection(target).insert(new_datas)
self.__update_backref(target, None, new_datas) uidname = target.uid_fieldname()[0] #MULTIPLE UID BROKEN HERE
leores = list(self.__collection(target).find({'_id':res}))[0]
self.__update_backref(target, leores[uidname], None, new_datas)
return str(res) return str(res)
## @brief Inserts a list of records in a given collection ## @brief Inserts a list of records in a given collection
@ -298,11 +309,13 @@ class MongoDbDatasource(object):
#  self.__update_backref(self.__class__, old_datas, new_datas) #  self.__update_backref(self.__class__, old_datas, new_datas)
#</pre> #</pre>
# #
#@param target LeObject child class #@param target LeObject child classa
#@param tuid mixed : The target UID (the value that will be inserted in
#back references)
#@param old_datas dict : datas state before update #@param old_datas dict : datas state before update
#@param new_datas dict : datas state after the update process #@param new_datas dict : datas state after the update process
#retun None #retun None
def __update_backref(self, target, old_datas, new_datas): def __update_backref(self, target, tuid, old_datas, new_datas):
#upd_dict is the dict that will allow to run updates in an optimized #upd_dict is the dict that will allow to run updates in an optimized
#way (or try to help doing it) #way (or try to help doing it)
# #
@ -365,7 +378,7 @@ class MongoDbDatasource(object):
vdict = {vtype: value} vdict = {vtype: value}
#fetch and store updated value #fetch and store updated value
new_bref_val = self.__back_ref_upd_one_value( new_bref_val = self.__back_ref_upd_one_value(
fname, fdh, bref_infos, **vdict) fname, fdh, tuid, bref_infos, **vdict)
upd_dict[bref_cls][value][1][bref_fname] = new_bref_val upd_dict[bref_cls][value][1][bref_fname] = new_bref_val
else: else:
#fdh is a single ref so the process is simpler, we do not have #fdh is a single ref so the process is simpler, we do not have
@ -392,7 +405,7 @@ class MongoDbDatasource(object):
upd_dict[bref_cls][uid_val][1][bref_fname]) upd_dict[bref_cls][uid_val][1][bref_fname])
#fetche and store updated value #fetche and store updated value
new_bref_val = self.__back_ref_upd_one_value( new_bref_val = self.__back_ref_upd_one_value(
fname, fdh , **vdict) fname, fdh, tuid, **vdict)
upd_dict[bref_cls][uid_val][1][bref_fname] = new_bref_val upd_dict[bref_cls][uid_val][1][bref_fname] = new_bref_val
#Now we've got our upd_dict ready. #Now we've got our upd_dict ready.
#running the updates #running the updates
@ -429,82 +442,62 @@ class MongoDbDatasource(object):
##@brief Prepare a one value back reference update ##@brief Prepare a one value back reference update
#@param fname str : the source Reference field name #@param fname str : the source Reference field name
#@param fdh DataHandler : the source Reference DataHandler #@param fdh DataHandler : the source Reference DataHandler
#@param tuid mixed : the uid of the Leo that make reference to the backref
#@param bref_infos tuple : as returned by __bref_get_check() method #@param bref_infos tuple : as returned by __bref_get_check() method
#@param old mixed : (optional **values) the old value #@param old mixed : (optional **values) the old value
#@param new mixed : (optional **values) the new value #@param new mixed : (optional **values) the new value
#@return the new back reference field value #@return the new back reference field value
def __back_ref_upd_one_value(self, fname, fdh, bref_infos, **values): def __back_ref_upd_one_value(self, fname, fdh, tuid, bref_infos, **values):
bref_cls, bref_leo, bref_dh, bref_val = bref_infos bref_cls, bref_leo, bref_dh, bref_val = bref_infos
oldd = 'old' in values oldd = 'old' in values
newd = 'new' in values newdd = 'new' in values
if oldd: if bref_val is None:
# bref_val = bref_dh.empty()
# We got an old value. It can be an update or a delete if issubclass(bref_dh.__class__, MultipleRef):
# if oldd and newdd:
old_value = values['old'] if tuid not in bref_val:
bref_cls, bref_leo, bref_dh, bref_val = self.__bref_get_check(
bref_cls, old_value, bref_fname)
if issubclass(bref_dh.__class__, MultipleRef):
#
# Multiple ref update (iterable)
if old_value not in bref_val:
raise MongodbConsistencyError("The value we want to \ raise MongodbConsistencyError("The value we want to \
replace in this back reference update was not found in the back referenced \ delete in this back reference update was not found in the back referenced \
object : %s field %s" % (bref_leo, ref_fname)) object : %s field %s. Value was : '%s'" % (bref_leo, ref_fname, tuid))
if isinstance(old_value, set): return bref_val
#Specific handling for set (values are not indexed) elif oldd and not newdd:
bref_val -= set([old_value]) #deletion
if newd: old_value = values['old']
# update value if tuid not in bref_val:
bref_val |= set([new_datas[fname]]) raise MongodbConsistencyError("The value we want to \
delete in this back reference update was not found in the back referenced \
object : %s field %s. Value was : '%s'" % (bref_leo, ref_fname, tuid))
if isinstance(bref_val, set):
bref_val -= set([tuid])
else: else:
# Assert that we can handles all other iterable this del(bref_val[bref_val.index(tuid)])
#way elif not oldd and newdd:
for ki, val in bref_val: if tuid in bref_val:
if val == old_value: raise MongodbConsistencyError("The value we want to \
if newd: add in this back reference update was found in the back referenced \
#Update object : %s field %s. Value was : '%s'" % (bref_leo, ref_fname, tuid))
bref_val[ki] = values['new'] if isinstance(bref_val, set):
else: bref_val |= set([tuid])
#Deletion
del(bref_val[ki])
break
else:
raise LodelFatalError("This error should never be \
raised ! We just checked that oldv is in bref_val...")
else:
#Single ref handling
if bref_val != values['old']:
raise MongoDbConsistencyError("The value we wanted to \
update do not match excpected value during aback reference singleReference \
update : expected value was '%s' but found '%s' in field '%s' of leo %s" % (
old_value, bref_val, ref_fname, bref_leo))
if newd:
#update
bref_val = values['new']
else: else:
#delete bref_val.append(tuid)
if not hasattr(bref_dh, "default"): else:
raise MongoDbConsistencyError("Unable to delete a \ #Single value backref
if oldd and newdd:
if bref_val != tuid:
raise MongodbConsistencyError("The backreference doesn't \
have expected value. Expected was %s but found %s in '%s' field of %s" % (
tuid, bref_val, bref_fname, bref_leo))
return bref_val
elif oldd and not newdd:
#deletion
if not hasattr(bref_dh, "default"):
raise MongoDbConsistencyError("Unable to delete a \
value for a back reference update. The concerned field don't have a default \ value for a back reference update. The concerned field don't have a default \
value : in %s field %s" % (bref_leo, ref_fname)) value : in %s field %s" % (bref_leo, ref_fname))
bref_val = getattr(bref_dh, "default") bref_val = getattr(bref_dh, "default")
elif newd: elif not oldd and newdd:
#It's an "insert" bref_val = tuid
new_value = values['new']
if issubclass(bref_dh.__class__, MultipleRef):
if bref_val is None:
bref_val = bref_dh.empty()
if isinstance(bref_val, set):
bref_val |= set([new_value])
else:
bref_val.append(new_value)
else:
bref_val = new_value
return bref_val return bref_val
##@brief Fetch back reference informations ##@brief Fetch back reference informations
#@warning thank's to __update_backref_act() this method is useless #@warning thank's to __update_backref_act() this method is useless