暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

leobject.py 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #-*- coding: utf-8 -*-
  2. ## @package EditorialModel::leobject::leobject
  3. # @brief Main class to handle objects defined by the types of an Editorial Model
  4. # an instance of these objects is pedantically called LeObject !
  5. import re
  6. from EditorialModel.types import EmType
  7. class _LeObject(object):
  8. ## @brief The editorial model
  9. _model = None
  10. ## @brief The datasource
  11. _datasource = None
  12. _query_re = None
  13. _query_operators = ['=', '<=', '>=', '!=', '<', '>', ' in ', ' not in ']
  14. ## @brief Instantiate with a Model and a DataSource
  15. # @param **kwargs dict : datas usefull to instanciate a _LeObject
  16. def __init__(self, **kwargs):
  17. raise NotImplementedError("Abstract constructor")
  18. ## @brief create a new LeObject
  19. # @param data dict: a dictionnary of field:value to save
  20. # @return lodel_id int: new lodel_id of the newly created LeObject
  21. def insert(self, data):
  22. try:
  23. checked_data = self._check_data(data)
  24. lodel_id = self.datasource.insert(checked_data)
  25. except:
  26. raise
  27. return lodel_id
  28. ## @brief update an existing LeObject
  29. # @param lodel_id int | (int): lodel_id of the object(s) where to apply changes
  30. # @param data dict: dictionnary of field:value to save
  31. # @param update_filters string | (string): list of string of update filters
  32. # @return okay bool: True on success, it will raise on failure
  33. def update(self, lodel_id, data, update_filters=None):
  34. if not lodel_id:
  35. lodel_id = ()
  36. elif isinstance(lodel_id, int):
  37. lodel_id = (lodel_id)
  38. try:
  39. checked_data = self._check_data(data)
  40. datasource_filters = self._prepare_filters(update_filters)
  41. okay = self.datasource.update(lodel_id, checked_data, datasource_filters)
  42. except:
  43. raise
  44. return okay
  45. ## @brief delete an existing LeObject
  46. # @param lodel_id int | (int): lodel_id of the object(s) to delete
  47. # @param delete_filters string | (string): list of string of delete filters
  48. # @return okay bool: True on success, it will raise on failure
  49. def delete(self, lodel_id, delete_filters=None):
  50. if not lodel_id:
  51. lodel_id = ()
  52. elif isinstance(lodel_id, int):
  53. lodel_id = (lodel_id)
  54. try:
  55. datasource_filters = self._prepare_filters(delete_filters)
  56. okay = self.datasource.delete(lodel_id, datasource_filters)
  57. except:
  58. raise
  59. return okay
  60. ## @brief make a search to retrieve a collection of LeObject
  61. # @param
  62. # @param query_filters list : list of string of query filters (or tuple (FIELD, OPERATOR, VALUE) )
  63. # @return responses ({string:*}): a list of dict with field:value
  64. def get(self, query_filters, typename = None, classname = None):
  65. filters = list()
  66. for query in query_filters:
  67. if len(query) == 3 and not isinstance(query, str):
  68. filters.append(tuple(query))
  69. else:
  70. filters.append(self._split_filter(query))
  71. #Now filters is a list of tuple (FIELD, OPERATOR, VALUE
  72. #Begining to check the filters
  73. #Fetching EmType
  74. if typename is None:
  75. emtype = None
  76. else:
  77. emtype = self._model.component_from_name(typename, 'EmType')
  78. if not emtype:
  79. raise LeObjectQueryError("No such EmType : '%s'"%typename)
  80. #Fetching EmClass
  81. if classname is None:
  82. emclass = None
  83. else:
  84. emclass = self._model.component_from_name(classname, 'EmClass')
  85. if not emclass:
  86. raise LeObjectQueryError("No such EmClass : '%s'"%classname)
  87. #Checking that fields in the query_filters are correct
  88. if emtype is None and emclass is None:
  89. #Only fields from the object table are allowed
  90. for field,_,_ in filters:
  91. if field not in EditorialModel.classtype.common_fields:
  92. raise LeObjectQueryError("Not typename and no classname given, but the field %s is not in the common_fields list"%field)
  93. else:
  94. if emtype is None:
  95. field_l = emclass.fields()
  96. else:
  97. if not (emclass is None):
  98. if emtype.em_class != emclass:
  99. raise LeObjectQueryError("The EmType %s is not a specialisation of the EmClass %s"%(typename, classname))
  100. else:
  101. #Set emclass (to query the db ?
  102. emclass = emtype.em_class
  103. field_l = emtype.fields()
  104. #Checks that fields are in this type
  105. for field,_,_ in filters:
  106. if field not in [ f.name for f in fields_l ]:
  107. raise LeObjectQueryError("No field named '%s' in '%s'"%(field, typename))
  108. return self._datasource.get(emclass, emtype, filters)
  109. ## @brief check if data dict fits with the model
  110. # @param data dict: dictionnary of field:value to check
  111. # @return checked_data ({string:*}): a list of dict with field:value
  112. # @todo implent !
  113. def _check_data(self, data):
  114. checked_data = data
  115. return checked_data
  116. ## @brief Check and split a query filter
  117. # @note The query_filter format is "FIELD OPERATOR VALUE"
  118. # @param query_filter str : A query_filter string
  119. # @return a tuple (FIELD, OPERATOR, VALUE)
  120. @classmethod
  121. def _split_filter(cls, query_filter):
  122. if cls._query_re is None:
  123. cls._compile_query_re()
  124. matches = cls._query_re.match(query_filter)
  125. if not matches:
  126. raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
  127. result = (matches.group('field'), re.sub(r'\s', ' ', matches.group('operator'), count=0), matches.group('value').strip())
  128. for r in result:
  129. if len(r) == 0:
  130. raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
  131. return result
  132. ## @brief Compile the regex for query_filter processing
  133. # @note Set _LeObject._query_re
  134. @classmethod
  135. def _compile_query_re(cls):
  136. op_re_piece = '(?P<operator>(%s)'%cls._query_operators[0].replace(' ', '\s')
  137. for operator in cls._query_operators[1:]:
  138. op_re_piece += '|(%s)'%operator.replace(' ', '\s')
  139. op_re_piece += ')'
  140. cls._query_re = re.compile('^\s*(?P<field>[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>[^<>=!].*)\s*$', flags=re.IGNORECASE)
  141. pass
  142. class LeObjectError(Exception):
  143. pass
  144. class LeObjectQueryError(LeObjectError):
  145. pass