1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2025-11-02 04:20:55 +01:00

Automatic update of Back-references

This commit is contained in:
prieto 2016-08-25 16:11:41 +02:00
commit 57688e7afb
5 changed files with 164 additions and 89 deletions

View file

@ -121,7 +121,16 @@ class DataHandler(object):
# @todo A implémenter
def check_data_consistency(self, emcomponent, fname, datas):
return True
##@brief make consistency after a query
# @param emcomponent EmComponent : An EmComponent child class instance
# @param fname : the field name
# @param datas dict : dict storing fields values
# @return an Exception instance if fails else True
# @todo A implémenter
def make_consistency(self, emcomponent, fname, datas):
pass
##@brief This method is use by plugins to register new data handlers
@classmethod
def register_new_handler(cls, name, data_handler):
@ -201,6 +210,7 @@ class Reference(DataHandler):
#if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0]) or not isinstance(back_reference[1], str):
# raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str) but got : (%s, %s)" % (back_reference[0], back_reference[1]))
self.__back_reference = back_reference
self.back_ref = back_reference
super().__init__(internal=internal, **kwargs)
@ -232,6 +242,31 @@ class Reference(DataHandler):
return None, FieldValidationError("Some element of this references are not valids (don't fit with allowed_classes")
return value
##@brief Check datas consistency
# @param emcomponent EmComponent : An EmComponent child class instance
# @param fname : the field name
# @param datas dict : dict storing fields values
# @return an Exception instance if fails else True
# @todo A implémenter
def check_data_consistency(self, emcomponent, fname, datas):
dh = emcomponent.field(fname)
logger.debug(dh)
logger.info('Warning : multiple uid capabilities are broken here')
uid = datas[emcomponent.uid_fieldname()[0]]
target_class = self.back_ref[0]
target_field = self.back_ref[1]
target_uidfield = traget_class.uid_fieldname()[0]
value = datas[emcomponent.data(fname)]
obj = target_class.get((target_uidfield , '=', value))
if len(obj) == 0:
logger.warning('Object referenced does not exist')
return False
obj.set_data(target_field, uid)
obj.update()
return True
##@brief This class represent a data_handler for single reference to another object
#
@ -277,6 +312,73 @@ class MultipleRef(Reference):
def check_data_consistency(self, emcomponent, fname, datas):
return True
def construct_data(self, emcomponent, fname, datas, cur_value):
if cur_value == 'None' or cur_value is None or cur_value == '':
return None
emcomponent_fields = emcomponent.fields()
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
u_fname = emcomponent.uid_fieldname()
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
if isinstance(cur_value, str):
value = cur_value.split(',')
l_value = [uidtype.cast_type(uid) for uid in value]
elif isinstance(cur_value, list):
l_value = list()
for value in cur_value:
if isinstance(value,uidtype.cast_type):
l_value.append(value)
else:
raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
else:
l_value = None
if l_value is not None:
if self.back_ref is not None:
br_class = self.back_ref[0]
for br_id in l_value:
query_filters = list()
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
br_obj = br_class.get(query_filters)
if len(br_obj) != 0:
br_list = br_obj[0].data(self.back_ref[1])
if br_list is None:
br_list = list()
if br_id not in br_list:
br_list.append(br_id)
logger.info('The referenced object has to be updated')
return l_value
def make_consistency(self, emcomponent, fname, datas):
dh = emcomponent.field(fname)
logger.info('Warning : multiple uid capabilities are broken here')
uid = datas[emcomponent.uid_fieldname()[0]]
if self.back_ref is not None:
target_class = self.back_ref[0]
target_field = self.back_ref[1]
target_uidfield = target_class.uid_fieldname()[0]
l_value = datas[fname]
if l_value is not None:
for value in l_value:
query_filters = list()
query_filters.append((target_uidfield , '=', value))
obj = target_class.get(query_filters)
if len(obj) == 0:
logger.warning('Object referenced does not exist')
return False
l_uids_ref = obj[0].data(target_field)
if l_uids_ref is None:
l_uids_ref = list()
if uid not in l_uids_ref:
l_uids_ref.append(uid)
obj[0].set_data(target_field, l_uids_ref)
obj[0].update()
## @brief Class designed to handle datas access will fieldtypes are constructing datas
#
# This class is designed to allow automatic scheduling of construct_data calls.

View file

@ -31,43 +31,7 @@ class List(MultipleRef):
return val, expt
def construct_data(self, emcomponent, fname, datas, cur_value):
if cur_value == 'None' or cur_value is None or cur_value == '':
return None
emcomponent_fields = emcomponent.fields()
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
u_fname = emcomponent.uid_fieldname()
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
if isinstance(cur_value, str):
value = cur_value.split(',')
l_value = [uidtype.cast_type(uid) for uid in value]
elif isinstance(cur_value, list):
l_value = list()
for value in cur_value:
if isinstance(value,uidtype):
l_value.append(value)
else:
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
else:
l_value = None
if l_value is not None:
br_class = self.back_reference()[0]
for br_id in l_value:
query_filters = list()
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
br_obj = br_class.get(query_filters)
# if br_obj.__class__ not in
if len(br_obj) == 0:
raise ValueError("Not existing instance of class %s in back_reference" % br_class.__name__)
br_list = br_obj.data(self.back_reference()[1])
if br_id not in br_list:
br_list.append(br_id)
br_obj.set_data(self.back_reference()[1], br_list)
br_obj.update()
return l_value
return super().construct_data(emcomponent, fname, datas, cur_value)
##@brief Child class of MultipleRef where references are represented in the form of a python set
class Set(MultipleRef):
@ -90,34 +54,8 @@ class Set(MultipleRef):
return val, expt
def construct_data(self, emcomponent, fname, datas, cur_value):
if cur_value == 'None' or cur_value is None or cur_value == '':
return None
emcomponent_fields = emcomponent.fields()
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
u_fname = emcomponent.uid_fieldname()
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
if isinstance(cur_value, str):
value = cur_value.split(',')
l_value = [uidtype.cast_type(uid) for uid in value]
logger.debug("Valeur avec uidtype : %d" % l_value)
#l_value = [int(uid) for uid in value]
return list(l_value)
elif isinstance(cur_value, set):
l_value = list()
for value in cur_value:
if isinstance(value,uidtype):
l_value.append(value)
else:
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
return l_value
logger.debug(l_value)
else:
return None
return super().construct_data(emcomponent, fname, datas, cur_value)
##@brief Child class of MultipleRef where references are represented in the form of a python dict
class Map(MultipleRef):
@ -139,6 +77,45 @@ class Map(MultipleRef):
None if isinstance(expt, Exception) else value,
expt)
def construct_data(self, emcomponent, fname, datas, cur_value):
logger.info('WARNING : not well implemented...list are stored...not dict')
if cur_value == 'None' or cur_value is None or cur_value == '':
return None
emcomponent_fields = emcomponent.fields()
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
u_fname = emcomponent.uid_fieldname()
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
if isinstance(cur_value, str):
value = cur_value.split(',')
l_value = [uidtype.cast_type(uid) for uid in value]
elif isinstance(cur_value, list):
l_value = list()
for value in cur_value:
if isinstance(value,uidtype.cast_type):
l_value.append(value)
else:
raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
else:
l_value = None
if l_value is not None:
if self.back_ref is not None:
br_class = self.back_ref[0]
for br_id in l_value:
query_filters = list()
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
br_obj = br_class.get(query_filters)
if len(br_obj) != 0:
br_list = br_obj[0].data(self.back_ref[1])
if br_list is None:
br_list = list()
if br_id not in br_list:
br_list.append(br_id)
logger.info('The referenced object has to be updated')
return l_value
##@brief This Reference class is designed to handler hierarchy with some constraint
class Hierarch(MultipleRef):
@ -161,25 +138,4 @@ class Hierarch(MultipleRef):
return val, expt
def construct_data(self, emcomponent, fname, datas, cur_value):
if cur_value == 'None' or cur_value is None or cur_value == '':
return None
emcomponent_fields = emcomponent.fields()
data_handler = None
if fname in emcomponent_fields:
data_handler = emcomponent_fields[fname]
u_fname = emcomponent.uid_fieldname()
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
if isinstance(cur_value, str):
value = cur_value.split(',')
l_value = [uidtype.cast_type(uid) for uid in value]
return list(l_value)
elif isinstance(cur_value, list):
l_value = list()
for value in cur_value:
if isinstance(value,uidtype):
l_value.append(value)
else:
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
return l_value
else:
return None
return super().construct_data(emcomponent, fname, datas, cur_value)

View file

@ -471,7 +471,7 @@ construction and consitency when datas are not complete\n")
if not ftype.is_internal() or ftype.internal != 'autosql'
}
return ret
## @brief Check datas consistency
# 
# @warning assert that datas is complete
@ -490,6 +490,11 @@ construction and consitency when datas are not complete\n")
if len(err_l) > 0:
raise LeApiDataCheckError("Datas consistency checks fails", err_l)
@classmethod
def make_consistency(cls, datas):
for fname, dh in cls._fields.items():
ret = dh.make_consistency(cls, fname, datas)
## @brief Add a new instance of LeObject
# @return a new uid en case of success, False otherwise
@classmethod

View file

@ -475,6 +475,8 @@ class LeInsertQuery(LeQuery):
def _query(self, datas):
datas = self._target_class.prepare_datas(datas, True, False)
id_inserted = self._rw_datasource.insert(self._target_class,datas)
# To put in a hook ??
self._target_class.make_consistency(datas=res_datas)
return id_inserted
"""
## @brief Implements an insert query operation, with multiple insertions
@ -565,6 +567,8 @@ target to LeUpdateQuery constructor"
res = self._rw_datasource.update(
self._target_class, filters, [],
res_datas)
# To put in a hook ??
self._target_class.make_consistency(datas=res_datas)
return res
## @brief Execute the update query

View file

@ -3,6 +3,10 @@
<head>
<meta charset="UTF-8" />
<title>{% block title %}{% endblock %}</title>
<!-- Bootstrap -->
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
{% block style %}{% endblock %}
{% block scripts %}{% endblock %}
</head>
@ -11,5 +15,9 @@
{% block content %}{% endblock %}
</div>
<script type="text/javascript">{% block javascript %}{% endblock %}</script>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="bootstrap/js/bootstrap.min.js"></script>
</body>
</html>