Browse Source

Bugfixes in leobject and queries classes

Yann Weber 9 years ago
parent
commit
76f002d06c
2 changed files with 74 additions and 33 deletions
  1. 4
    4
      lodel/leapi/leobject.py
  2. 70
    29
      lodel/leapi/query.py

+ 4
- 4
lodel/leapi/leobject.py View File

@@ -130,9 +130,9 @@ class LeObject(object):
130 130
     @classmethod
131 131
     def fieldnames(cls, include_ro = False):
132 132
         if not include_ro:
133
-            return [ fname for fname in self._fields if not self._fields[fname].is_internal() ]
133
+            return [ fname for fname in cls._fields if not cls._fields[fname].is_internal() ]
134 134
         else:
135
-            return list(self._fields.keys())
135
+            return list(cls._fields.keys())
136 136
  
137 137
     @classmethod
138 138
     def name2objname(cls, name):
@@ -166,14 +166,14 @@ class LeObject(object):
166 166
     def is_abstract(cls):
167 167
         return cls._abstract
168 168
     
169
-    ##@brief Field data handler gettet
169
+    ##@brief Field data handler getter
170 170
     #@param fieldname str : The field name
171 171
     #@return A datahandler instance
172 172
     #@throw NameError if the field doesn't exist
173 173
     @classmethod
174 174
     def field(cls, fieldname):
175 175
         try:
176
-            return cls._fields[field_uid]
176
+            return cls._fields[fieldname]
177 177
         except KeyError:
178 178
             raise NameError("No field named '%s' in %s" % ( field_uid,
179 179
                                                             cls.__name__))

+ 70
- 29
lodel/leapi/query.py View File

@@ -45,7 +45,7 @@ class LeQuery(object):
45 45
             raise NotImplementedError("Abstract class")
46 46
         if not issubclass(target_class, LeObject):
47 47
             raise TypeError("target class has to be a child class of LeObject")
48
-        self.__target_class = target_class
48
+        self._target_class = target_class
49 49
     
50 50
     ##@brief Execute a query and return the result
51 51
     # @param **datas
@@ -56,18 +56,18 @@ class LeQuery(object):
56 56
     #elsewhere
57 57
     def execute(self, datasource, datas = None):
58 58
         if len(datas) > 0:
59
-            self.__target_class.check_datas_value(
59
+            self._target_class.check_datas_value(
60 60
                                                     datas,
61 61
                                                     **self._data_check_args)
62
-            self.__target_class.prepare_datas() #not yet implemented
62
+            self._target_class.prepare_datas() #not yet implemented
63 63
         if self._hook_prefix is None:
64 64
             raise NotImplementedError("Abstract method")
65 65
         LodelHook.call_hook(    self._hook_prefix+'_pre',
66
-                                self.__target_class,
66
+                                self._target_class,
67 67
                                 datas)
68 68
         ret = self.__query(datasource, **datas)
69 69
         ret = LodelHook.call_hook(  self._hook_prefix+'_post',
70
-                                    self.__target_class,
70
+                                    self._target_class,
71 71
                                     ret)
72 72
         return ret
73 73
     
@@ -76,11 +76,22 @@ class LeQuery(object):
76 76
     # @return query result
77 77
     def __query(self, **datas):
78 78
         raise NotImplementedError("Asbtract method")
79
+    
80
+    ##@return a dict with query infos
81
+    def dump_infos(self):
82
+        return {'target_class': self._target_class}
83
+
84
+    def __repr__(self):
85
+        ret = "<{classname} target={target_class}>"
86
+        return ret.format(
87
+                            classname=self.__class__.__name__,
88
+                            target_class = self._target_class)
89
+        
79 90
 
80 91
 class LeFilteredQuery(LeQuery):
81 92
     
82 93
     ##@brief The available operators used in query definitions
83
-    query_operators = [
94
+    _query_operators = [
84 95
                         '=',
85 96
                         '<=',
86 97
                         '>=',
@@ -91,6 +102,9 @@ class LeFilteredQuery(LeQuery):
91 102
                         'not in',
92 103
                         'like',
93 104
                         'not like']
105
+    
106
+    ##@brief Regular expression to process filters
107
+    _query_re = None
94 108
 
95 109
     ##@brief Abtract constructor for queries with filter
96 110
     # @param target_class LeObject : class of object the query is about
@@ -99,16 +113,29 @@ class LeFilteredQuery(LeQuery):
99 113
     #   For tuple (FIELD,OPERATOR,VALUE)
100 114
     def __init__(self, target_class, query_filters = None):
101 115
         super().__init__(target_class)
102
-        ##@brief The query filter
116
+        ##@brief The query filter tuple(std_filter, relational_filters)
103 117
         self.__query_filter = None
104
-        self.set_query_filter(query_filter)
118
+        self.set_query_filter(query_filters)
105 119
     
106 120
     ##@brief Add filter(s) to the query
107 121
     #@param query_filter list|tuple|str : A single filter or a list of filters
108 122
     #@see LeFilteredQuery._prepare_filters()
109
-    def filter(self, query_filter):
110
-        pass
123
+    def set_query_filter(self, query_filter):
124
+        if isinstance(query_filter, str):
125
+            query_filter = [query_filter]
126
+        self.__query_filter = self._prepare_filters(query_filter)
127
+
128
+    def dump_infos(self):
129
+        ret = super().dump_infos()
130
+        ret['query_filter'] = self.__query_filter
131
+        return ret
111 132
 
133
+    def __repr__(self):
134
+        ret = "<{classname} target={target_class} query_filter={query_filter}>"
135
+        return ret.format(
136
+                            classname=self.__class__.__name__,
137
+                            query_filter = self.__query_filter,
138
+                            target_class = self._target_class)
112 139
     ## @brief Prepare filters for datasource
113 140
     # 
114 141
     #A filter can be a string or a tuple with len = 3.
@@ -140,18 +167,20 @@ class LeFilteredQuery(LeQuery):
140 167
     #@param filters_l list : This list of str or tuple (or both)
141 168
     #@return a tuple(FILTERS, RELATIONNAL_FILTERS
142 169
     #@todo move this doc in another place (a dedicated page ?)
143
-    @classmethod
144
-    def _prepare_filters(cls, filters_l):
170
+    def _prepare_filters(self, filters_l):
145 171
         filters = list()
146 172
         res_filters = list()
147 173
         rel_filters = list()
148 174
         err_l = dict()
149 175
         #Splitting in tuple if necessary
150
-        for fil in filters_l:
176
+        for i,fil in enumerate(filters_l):
151 177
             if len(fil) == 3 and not isinstance(fil, str):
152 178
                 filters.append(tuple(fil))
153 179
             else:
154
-                filters.append(cls.split_filter(fil))
180
+                try:
181
+                    filters.append(self.split_filter(fil))
182
+                except ValueError as e:
183
+                    err_l["filter %d" % i] = e
155 184
 
156 185
         for field, operator, value in filters:
157 186
             # Spliting field name to be able to detect a relational field
@@ -165,7 +194,7 @@ class LeFilteredQuery(LeQuery):
165 194
 field name" % fieldname)
166 195
                 continue   
167 196
             # Checking field against target_class
168
-            ret = self.__check_field(self.__target_class, field)
197
+            ret = self.__check_field(self._target_class, field)
169 198
             if isinstance(ret, Exception):
170 199
                 err_l[field] = ret
171 200
                 continue
@@ -178,8 +207,8 @@ a relational field, but %s.%s was present in the filter"
178 207
                                                 field,
179 208
                                                 ref_field))
180 209
             # Prepare relational field
181
-            if cls.field(field).is_reference():
182
-                ret = cls._prepare_relational_fields(field, ref_field)
210
+            if self._target_class.field(field).is_reference():
211
+                ret = self._prepare_relational_fields(field, ref_field)
183 212
                 if isinstance(ret, Exception):
184 213
                     err_l[field] = ret
185 214
                 else:
@@ -267,7 +296,7 @@ a relational field, but %s.%s was present in the filter"
267 296
     #@return a well formed relational filter tuple or an Exception instance
268 297
     @classmethod
269 298
     def __prepare_relational_fields(cls, fieldname, ref_field = None):
270
-        datahandler = self.__target_class.field(fieldname)
299
+        datahandler = self._target_class.field(fieldname)
271 300
         # now we are going to fetch the referenced class to see if the
272 301
         # reference field is valid
273 302
         ref_classes = datahandler.linked_classes
@@ -300,14 +329,14 @@ class LeInsertQuery(LeQuery):
300 329
     ## @brief Implements an insert query operation, with only one insertion
301 330
     # @param **datas : datas to be inserted
302 331
     def __query(self, datasource, **datas):
303
-        nb_inserted = datasource.insert(self.__target_class,**datas)
332
+        nb_inserted = datasource.insert(self._target_class,**datas)
304 333
         if nb_inserted < 0:
305 334
             raise LeQueryError("Insertion error")
306 335
         return nb_inserted
307 336
     ## @brief Implements an insert query operation, with multiple insertions
308 337
     # @param datas : list of **datas to be inserted
309 338
     def __query(self, datasource, datas):
310
-        nb_inserted = datasource.insert_multi(self.__target_class,datas_list)
339
+        nb_inserted = datasource.insert_multi(self._target_class,datas_list)
311 340
         if nb_inserted < 0:
312 341
             raise LeQueryError("Multiple insertions error")
313 342
         return nb_inserted
@@ -330,9 +359,9 @@ class LeUpdateQuery(LeFilteredQuery):
330 359
     # @exception when the number of updated items is not as expected
331 360
     def __query(self, datasource, **datas):
332 361
         # select _uid corresponding to query_filter
333
-        l_uids=datasource.select(self.__target_class,list(self.__target_class.getuid()),query_filter,None, None, None, None, 0, False)
362
+        l_uids=datasource.select(self._target_class,list(self._target_class.getuid()),query_filter,None, None, None, None, 0, False)
334 363
         # list of dict l_uids : _uid(s) of the objects to be updated, corresponding datas
335
-        nb_updated = datasource.update(self.__target_class,l_uids, **datas)
364
+        nb_updated = datasource.update(self._target_class,l_uids, **datas)
336 365
         if nb_updated != len(l_uids):
337 366
             raise LeQueryError("Number of updated items: %d is not as expected: %d " % (nb_updated, len(l_uids)))
338 367
         return nb_updated
@@ -358,9 +387,9 @@ class LeDeleteQuery(LeFilteredQuery):
358 387
     # @exception when the number of deleted items is not as expected
359 388
     def __query(self, datasource):
360 389
         # select _uid corresponding to query_filter
361
-        l_uids=datasource.select(self.__target_class,list(self.__target_class.getuid()),query_filter,None, None, None, None, 0, False)
390
+        l_uids=datasource.select(self._target_class,list(self._target_class.getuid()),query_filter,None, None, None, None, 0, False)
362 391
         # list of dict l_uids : _uid(s) of the objects to be deleted
363
-        nb_deleted = datasource.update(self.__target_class,l_uids, **datas)
392
+        nb_deleted = datasource.update(self._target_class,l_uids, **datas)
364 393
         if nb_deleted != len(l_uids):
365 394
             raise LeQueryError("Number of deleted items %d is not as expected %d " % (nb_deleted, len(l_uids)))
366 395
         return nb_deleted
@@ -399,10 +428,10 @@ class LeGetQuery(LeFilteredQuery):
399 428
 
400 429
         if 'field_list' not in kwargs:
401 430
             #field_list = target_class.get_field_list
402
-            field_list = target_class.fieldnames()
431
+            self.__field_list = target_class.fieldnames(include_ro = True)
403 432
         else:
404 433
             #target_class.check_fields(kwargs['field_list'])
405
-            field_list = kwargs['field_list']
434
+            self.__field_list = kwargs['field_list']
406 435
         if 'order' in kwargs:
407 436
             #check kwargs['order']
408 437
             self.__order = kwargs['order']
@@ -430,11 +459,23 @@ class LeGetQuery(LeFilteredQuery):
430 459
 
431 460
     ##@brief Implements select query operations
432 461
     # @returns a list containing the item(s)
433
-
434 462
     def __query(self, datasource):
435 463
         # select datas corresponding to query_filter
436
-        l_datas=datasource.select(self.__target_class,list(self.field_list),self.query_filter,None, self.__order, self.__group, self.__limit, self.offset, False)
464
+        l_datas=datasource.select(self._target_class,list(self.field_list),self.query_filter,None, self.__order, self.__group, self.__limit, self.offset, False)
437 465
         return l_datas
438
-        
466
+    
467
+    ##@return a dict with query infos
468
+    def dump_infos(self):
469
+        ret = super().dump_infos()
470
+        ret.update( {   'field_list' : self.__field_list,
471
+                        'order' : self.__order,
472
+                        'group' : self.__group,
473
+                        'limit' : self.__limit,
474
+                        'offset': self.__offset,
475
+        })
476
+        return ret
439 477
 
478
+    def __repr__(self):
479
+        ret = "<LeGetQuery target={target_class} filter={query_filter} field_list={field_list} order={order} group={group} limit={limit} offset={offset}>"
480
+        return ret.format(**self.dump_infos())
440 481
 

Loading…
Cancel
Save