Browse Source

Add tests for filtered queries + bugfixes

- adds tests on filter parse & check
 - standart filters parse & check
 - relational filters parse & check
- bugfixes related to tests in query.py
- update the example and the test EM
- bugfixes in admin script
Yann Weber 8 years ago
parent
commit
9781577cb6

BIN
examples/em_test.pickle View File


+ 1
- 1
globconf.d/lodel2.ini View File

@@ -5,7 +5,7 @@ plugins_path = plugins
5 5
 plugins = dummy, webui
6 6
 
7 7
 [lodel2.logging.stderr]
8
-level = DEBUG
8
+level = ERROR
9 9
 filename = -
10 10
 context = True
11 11
 

+ 4
- 1
lodel/leapi/datahandlers/references.py View File

@@ -77,7 +77,10 @@ class Hierarch(MultipleRef):
77 77
     # @param max_depth int | None :  limit of depth
78 78
     # @param max_childs int | Nine : maximum number of childs by nodes
79 79
     def __init__(self, back_reference, max_depth = None, max_childs = None, **kwargs):
80
-        super().__init__(back_reference = back_reference, max_depth = max_depth, )
80
+        super().__init__(   back_reference = back_reference,
81
+                            max_depth = max_depth,
82
+                            max_childs = max_childs,
83
+                            **kwargs)
81 84
 
82 85
     def _check_data_value(self, value):
83 86
         value, expt = super()._check_data_value(value)

+ 46
- 7
lodel/leapi/query.py View File

@@ -183,6 +183,7 @@ class LeFilteredQuery(LeQuery):
183 183
                     err_l["filter %d" % i] = e
184 184
 
185 185
         for field, operator, value in filters:
186
+            err_key = "%s %s %s" % (field, operator, value) #to push in err_l
186 187
             # Spliting field name to be able to detect a relational field
187 188
             field_spl = field.split('.')
188 189
             if len(field_spl) == 2:
@@ -198,19 +199,33 @@ field name" % fieldname)
198 199
             if isinstance(ret, Exception):
199 200
                 err_l[field] = ret
200 201
                 continue
201
-            # Check that the field is relational if ref_field given
202
-            if ref_field is not None and not cls.field(field).is_reference():
202
+            field_datahandler = self._target_class.field(field)
203
+            if ref_field is not None and not field_datahandler.is_reference():
203 204
                 # inconsistency
204
-                err_l[field] = NameError(   "The field '%s' in %s is not\
205
+                err_l[field] = NameError(   "The field '%s' in %s is not \
205 206
 a relational field, but %s.%s was present in the filter"
206 207
                                             % ( field,
208
+                                                self._target_class.__name__,
207 209
                                                 field,
208 210
                                                 ref_field))
209
-            # Prepare relational field
210
-            if self._target_class.field(field).is_reference():
211
+            if field_datahandler.is_reference():
212
+                #Relationnal field
213
+                if ref_field is None:
214
+                    # ref_field default value
215
+                    ref_uid = set([ lc._uid for lc in field_datahandler.linked_classes])
216
+                    if len(ref_uid) == 1:
217
+                        ref_field = ref_uid[0]
218
+                    else:
219
+                        if len(ref_uid) > 1:
220
+                            err_l[err_key] = RuntimeError("The referenced classes are identified by fields with different name. Unable to determine wich field to use for the reference")
221
+                        else:
222
+                            err_l[err_key] = RuntimeError("Unknow error when trying to determine wich field to use for the relational filter")
223
+                        continue
224
+                # Prepare relational field
211 225
                 ret = self._prepare_relational_fields(field, ref_field)
212 226
                 if isinstance(ret, Exception):
213
-                    err_l[field] = ret
227
+                    err_l[err_key] = ret
228
+                    continue
214 229
                 else:
215 230
                     rel_filters.append((ret, operator, value))
216 231
             else:
@@ -221,6 +236,30 @@ a relational field, but %s.%s was present in the filter"
221 236
                                         "Error while preparing filters : ",
222 237
                                         err_l)
223 238
         return (res_filters, rel_filters)
239
+    
240
+    ## @brief Prepare & check relational field
241
+    #
242
+    # The result is a tuple with (field, ref_field, concerned_classes), with :
243
+    # - field the target_class field name
244
+    # - ref_field the concerned_classes field names
245
+    # - concerned_classes a set of concerned LeObject classes
246
+    # @param field str : The target_class field name
247
+    # @param ref_field str : The referenced class field name
248
+    # @return a tuple(field, concerned_classes, ref_field) or an Exception class instance
249
+    def _prepare_relational_fields(self,field, ref_field):
250
+        field_dh = self._target_class.field(field)
251
+        concerned_classes = []
252
+        linked_classes = [] if field_dh.linked_classes is None else field_dh.linked_classes
253
+        for l_class in linked_classes:
254
+            try:
255
+                l_class.field(ref_field)
256
+                concerned_classes.append(l_class)
257
+            except KeyError:
258
+                pass
259
+        if len(concerned_classes) > 0:
260
+            return (field, ref_field, concerned_classes)
261
+        else:
262
+            return ValueError("None of the linked class of field %s has a field named '%s'" % (field, ref_field))
224 263
 
225 264
     ## @brief Check and split a query filter
226 265
     # @note The query_filter format is "FIELD OPERATOR VALUE"
@@ -249,7 +288,7 @@ a relational field, but %s.%s was present in the filter"
249 288
         for operator in cls._query_operators[1:]:
250 289
             op_re_piece += '|(%s)'%operator.replace(' ', '\s')
251 290
         op_re_piece += ')'
252
-        cls._query_re = re.compile('^\s*(?P<field>(((superior)|(subordinate))\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>.*)\s*$', flags=re.IGNORECASE)
291
+        cls._query_re = re.compile('^\s*(?P<field>([a-z_][a-z0-9\-_]*\.)?[a-z_][a-z0-9\-_]*)\s*'+op_re_piece+'\s*(?P<value>.*)\s*$', flags=re.IGNORECASE)
253 292
         pass
254 293
 
255 294
     @classmethod

+ 3
- 1
scripts/admin.py View File

@@ -4,7 +4,9 @@ import sys
4 4
 import os, os.path
5 5
 
6 6
 sys.path.append(os.path.dirname(os.getcwd()+'/..'))
7
-import loader
7
+from lodel.settings.settings import Settings as settings
8
+settings('globconf.d')
9
+from lodel.settings import Settings
8 10
 
9 11
 def generate_dyncode(model_file, translator):
10 12
     from lodel.editorial_model.model import EditorialModel

BIN
tests/editorial_model.pickle View File


+ 18
- 0
tests/leapi/query/test_filtered.py View File

@@ -115,3 +115,21 @@ class LeFilteredQueryTestCase(unittest.TestCase):
115 115
                                         'lodel_id %s %s' % (op,v))
116 116
                     self.assertEqual(   get_q.dump_infos()['query_filter'],
117 117
                                         ([('lodel_id',op,v)],[]))
118
+    
119
+    def test_rel_filters(self):
120
+        """ Testing relational filters recognition """
121
+        test_datas = [  (   dyncode.Subsection,
122
+                            'parent.lodel_id = 42',
123
+                            (   [],
124
+                                [(('parent', 'lodel_id', [dyncode.Section]),'=','42')])),
125
+                        (   dyncode.Section,
126
+                            'childs.lodel_id = 42',
127
+                            (   [],
128
+                                [(('childs', 'lodel_id', [dyncode.Subsection]),'=','42')]))
129
+                        ]
130
+
131
+        for le_class, q_filter_arg, e_qfilter in test_datas:
132
+            get_q = LeGetQuery(le_class, q_filter_arg)
133
+            qinfos = get_q.dump_infos()
134
+            self.assertEqual(   qinfos['query_filter'],
135
+                                e_qfilter)

Loading…
Cancel
Save