|
@@ -109,10 +109,10 @@ class LeFilteredQuery(LeQuery):
|
109
|
109
|
_query_re = None
|
110
|
110
|
|
111
|
111
|
##@brief Abtract constructor for queries with filter
|
112
|
|
- # @param target_class LeObject : class of object the query is about
|
113
|
|
- # @param query_filters list : with a tuple (only one filter) or a list of tuple
|
114
|
|
- # or a dict: {OP,list(filters)} with OP = 'OR' or 'AND
|
115
|
|
- # For tuple (FIELD,OPERATOR,VALUE)
|
|
112
|
+ #@param target_class LeObject : class of object the query is about
|
|
113
|
+ #@param query_filters list : with a tuple (only one filter) or a list of
|
|
114
|
+ # tuple or a dict: {OP,list(filters)} with OP = 'OR' or 'AND for tuple
|
|
115
|
+ # (FIELD,OPERATOR,VALUE)
|
116
|
116
|
def __init__(self, target_class, query_filters = None):
|
117
|
117
|
super().__init__(target_class)
|
118
|
118
|
##@brief The query filter tuple(std_filter, relational_filters)
|
|
@@ -214,14 +214,19 @@ a relational field, but %s.%s was present in the filter"
|
214
|
214
|
#Relationnal field
|
215
|
215
|
if ref_field is None:
|
216
|
216
|
# ref_field default value
|
217
|
|
- ref_uid = set([ lc._uid for lc in field_datahandler.linked_classes])
|
|
217
|
+ ref_uid = set(
|
|
218
|
+ [lc._uid for lc in field_datahandler.linked_classes])
|
218
|
219
|
if len(ref_uid) == 1:
|
219
|
220
|
ref_field = ref_uid[0]
|
220
|
221
|
else:
|
221
|
222
|
if len(ref_uid) > 1:
|
222
|
|
- 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")
|
|
223
|
+ msg = "The referenced classes are identified by \
|
|
224
|
+fields with different name. Unable to determine wich field to use for the \
|
|
225
|
+reference"
|
223
|
226
|
else:
|
224
|
|
- err_l[err_key] = RuntimeError("Unknow error when trying to determine wich field to use for the relational filter")
|
|
227
|
+ msg = "Unknow error when trying to determine wich \
|
|
228
|
+field to use for the relational filter"
|
|
229
|
+ err_l[err_key] = RuntimeError(msg)
|
225
|
230
|
continue
|
226
|
231
|
# Prepare relational field
|
227
|
232
|
ret = self._prepare_relational_fields(field, ref_field)
|
|
@@ -239,19 +244,22 @@ a relational field, but %s.%s was present in the filter"
|
239
|
244
|
err_l)
|
240
|
245
|
return (res_filters, rel_filters)
|
241
|
246
|
|
242
|
|
- ## @brief Prepare & check relational field
|
|
247
|
+ ##@brief Prepare & check relational field
|
243
|
248
|
#
|
244
|
249
|
# The result is a tuple with (field, ref_field, concerned_classes), with :
|
245
|
250
|
# - field the target_class field name
|
246
|
251
|
# - ref_field the concerned_classes field names
|
247
|
252
|
# - concerned_classes a set of concerned LeObject classes
|
248
|
|
- # @param field str : The target_class field name
|
249
|
|
- # @param ref_field str : The referenced class field name
|
250
|
|
- # @return a tuple(field, concerned_classes, ref_field) or an Exception class instance
|
|
253
|
+ #@param field str : The target_class field name
|
|
254
|
+ #@param ref_field str : The referenced class field name
|
|
255
|
+ #@return a tuple(field, concerned_classes, ref_field) or an Exception
|
|
256
|
+ # class instance
|
251
|
257
|
def _prepare_relational_fields(self,field, ref_field):
|
252
|
258
|
field_dh = self._target_class.field(field)
|
253
|
259
|
concerned_classes = []
|
254
|
|
- linked_classes = [] if field_dh.linked_classes is None else field_dh.linked_classes
|
|
260
|
+ linked_classes = field_dh.linked_classes
|
|
261
|
+ if linked_classes is None:
|
|
262
|
+ linked_classes = []
|
255
|
263
|
for l_class in linked_classes:
|
256
|
264
|
try:
|
257
|
265
|
l_class.field(ref_field)
|
|
@@ -261,7 +269,8 @@ a relational field, but %s.%s was present in the filter"
|
261
|
269
|
if len(concerned_classes) > 0:
|
262
|
270
|
return (field, ref_field, concerned_classes)
|
263
|
271
|
else:
|
264
|
|
- return ValueError("None of the linked class of field %s has a field named '%s'" % (field, ref_field))
|
|
272
|
+ msg = "None of the linked class of field %s has a field named '%s'"
|
|
273
|
+ return ValueError(msg % (field, ref_field))
|
265
|
274
|
|
266
|
275
|
## @brief Check and split a query filter
|
267
|
276
|
# @note The query_filter format is "FIELD OPERATOR VALUE"
|
|
@@ -274,23 +283,34 @@ a relational field, but %s.%s was present in the filter"
|
274
|
283
|
cls.__compile_query_re()
|
275
|
284
|
matches = cls._query_re.match(query_filter)
|
276
|
285
|
if not matches:
|
277
|
|
- raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
|
278
|
|
- result = (matches.group('field'), re.sub(r'\s', ' ', matches.group('operator'), count=0), matches.group('value').strip())
|
|
286
|
+ msg = "The query_filter '%s' seems to be invalid"
|
|
287
|
+ raise ValueError(msg % query_filter)
|
|
288
|
+ result = (
|
|
289
|
+ matches.group('field'),
|
|
290
|
+ re.sub(r'\s', ' ', matches.group('operator'), count=0),
|
|
291
|
+ matches.group('value').strip())
|
|
292
|
+
|
279
|
293
|
result = [r.strip() for r in result]
|
280
|
294
|
for r in result:
|
281
|
295
|
if len(r) == 0:
|
282
|
|
- raise ValueError("The query_filter '%s' seems to be invalid"%query_filter)
|
|
296
|
+ msg = "The query_filter '%s' seems to be invalid"
|
|
297
|
+ raise ValueError(msg % query_filter)
|
283
|
298
|
return result
|
284
|
299
|
|
285
|
300
|
## @brief Compile the regex for query_filter processing
|
286
|
301
|
# @note Set _LeObject._query_re
|
287
|
302
|
@classmethod
|
288
|
303
|
def __compile_query_re(cls):
|
289
|
|
- op_re_piece = '(?P<operator>(%s)'%cls._query_operators[0].replace(' ', '\s')
|
|
304
|
+ op_re_piece = '(?P<operator>(%s)'
|
|
305
|
+ op_re_piece %= cls._query_operators[0].replace(' ', '\s')
|
290
|
306
|
for operator in cls._query_operators[1:]:
|
291
|
307
|
op_re_piece += '|(%s)'%operator.replace(' ', '\s')
|
292
|
308
|
op_re_piece += ')'
|
293
|
|
- 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)
|
|
309
|
+
|
|
310
|
+ re_full = '^\s*(?P<field>([a-z_][a-z0-9\-_]*\.)?[a-z_][a-z0-9\-_]*)\s*'
|
|
311
|
+ re_full += op_re_piece+'\s*(?P<value>.*)\s*$'
|
|
312
|
+
|
|
313
|
+ cls._query_re = re.compile(re_full, flags=re.IGNORECASE)
|
294
|
314
|
pass
|
295
|
315
|
|
296
|
316
|
@classmethod
|
|
@@ -378,7 +398,8 @@ class LeInsertQuery(LeQuery):
|
378
|
398
|
## @brief Implements an insert query operation, with multiple insertions
|
379
|
399
|
# @param datas : list of **datas to be inserted
|
380
|
400
|
def __query(self, datas):
|
381
|
|
- nb_inserted = self._datasource.insert_multi(self._target_class,datas_list)
|
|
401
|
+ nb_inserted = self._datasource.insert_multi(
|
|
402
|
+ self._target_class,datas_list)
|
382
|
403
|
if nb_inserted < 0:
|
383
|
404
|
raise LeQueryError("Multiple insertions error")
|
384
|
405
|
return nb_inserted
|
|
@@ -411,7 +432,8 @@ class LeUpdateQuery(LeFilteredQuery):
|
411
|
432
|
None,
|
412
|
433
|
0,
|
413
|
434
|
False)
|
414
|
|
- # list of dict l_uids : _uid(s) of the objects to be updated, corresponding datas
|
|
435
|
+ # list of dict l_uids : _uid(s) of the objects to be updated,
|
|
436
|
+ # corresponding datas
|
415
|
437
|
nb_updated = self._datasource.update( self._target_class,
|
416
|
438
|
l_uids,
|
417
|
439
|
**datas)
|
|
@@ -464,14 +486,15 @@ class LeGetQuery(LeFilteredQuery):
|
464
|
486
|
_hook_prefix = 'leapi_get_'
|
465
|
487
|
|
466
|
488
|
##@brief Instanciate a new get query
|
467
|
|
- # @param target_class LeObject : class of object the query is about
|
468
|
|
- # @param query_filters dict : {OP, list of query filters }
|
469
|
|
- # or tuple (FIELD, OPERATOR, VALUE) )
|
470
|
|
- # @param field_list list|None : list of string representing fields see @ref leobject_filters
|
471
|
|
- # @param order list : A list of field names or tuple (FIELDNAME, [ASC | DESC])
|
472
|
|
- # @param group list : A list of field names or tuple (FIELDNAME, [ASC | DESC])
|
473
|
|
- # @param limit int : The maximum number of returned results
|
474
|
|
- # @param offset int : offset
|
|
489
|
+ #@param target_class LeObject : class of object the query is about
|
|
490
|
+ #@param query_filters dict : {OP, list of query filters }
|
|
491
|
+ # or tuple (FIELD, OPERATOR, VALUE) )
|
|
492
|
+ #@param field_list list|None : list of string representing fields see
|
|
493
|
+ # @ref leobject_filters
|
|
494
|
+ #@param order list : A list of field names or tuple (FIELDNAME,[ASC | DESC])
|
|
495
|
+ #@param group list : A list of field names or tuple (FIELDNAME,[ASC | DESC])
|
|
496
|
+ #@param limit int : The maximum number of returned results
|
|
497
|
+ #@param offset int : offset
|
475
|
498
|
def __init__(self, target_class, query_filter, **kwargs):
|
476
|
499
|
super().__init__(target_class, query_filter)
|
477
|
500
|
|
|
@@ -488,7 +511,8 @@ class LeGetQuery(LeFilteredQuery):
|
488
|
511
|
|
489
|
512
|
# Checking kwargs and assigning default values if there is some
|
490
|
513
|
for argname in kwargs:
|
491
|
|
- if argname not in ('field_list', 'order', 'group', 'limit', 'offset'):
|
|
514
|
+ if argname not in (
|
|
515
|
+ 'field_list', 'order', 'group', 'limit', 'offset'):
|
492
|
516
|
raise TypeError("Unexpected argument '%s'" % argname)
|
493
|
517
|
|
494
|
518
|
if 'field_list' not in kwargs:
|
|
@@ -508,14 +532,16 @@ class LeGetQuery(LeFilteredQuery):
|
508
|
532
|
if self.__limit <= 0:
|
509
|
533
|
raise ValueError()
|
510
|
534
|
except ValueError:
|
511
|
|
- raise ValueError("limit argument expected to be an interger > 0")
|
|
535
|
+ msg = "limit argument expected to be an interger > 0"
|
|
536
|
+ raise ValueError(msg)
|
512
|
537
|
if 'offset' in kwargs:
|
513
|
538
|
try:
|
514
|
539
|
self.__offset = int(kwargs['offset'])
|
515
|
540
|
if self.__offset < 0:
|
516
|
541
|
raise ValueError()
|
517
|
542
|
except ValueError:
|
518
|
|
- raise ValueError("offset argument expected to be an integer >= 0")
|
|
543
|
+ msg = "offset argument expected to be an integer >= 0"
|
|
544
|
+ raise ValueError(msg)
|
519
|
545
|
|
520
|
546
|
##@brief Set the field list
|
521
|
547
|
# @param field_list list | None : If None use all fields
|
|
@@ -526,12 +552,13 @@ class LeGetQuery(LeFilteredQuery):
|
526
|
552
|
for fieldname in field_list:
|
527
|
553
|
ret = self._check_field(self._target_class, fieldname)
|
528
|
554
|
if isinstance(ret, Exception):
|
529
|
|
- expt = NameError( "No field named '%s' in %s" % ( fieldname,
|
530
|
|
- self._target_class.__name__))
|
|
555
|
+ msg = "No field named '%s' in %s"
|
|
556
|
+ msg %= (fieldname, self._target_class.__name__)
|
|
557
|
+ expt = NameError(msg)
|
531
|
558
|
err_l[fieldname] = expt
|
532
|
559
|
if len(err_l) > 0:
|
533
|
|
- raise LeQueryError( msg = "Error while setting field_list in a get query",
|
534
|
|
- exceptions = err_l)
|
|
560
|
+ msg = "Error while setting field_list in a get query"
|
|
561
|
+ raise LeQueryError(msg = msg, exceptions = err_l)
|
535
|
562
|
self.__field_list = list(set(field_list))
|
536
|
563
|
|
537
|
564
|
##@brief Execute the get query
|
|
@@ -565,6 +592,8 @@ class LeGetQuery(LeFilteredQuery):
|
565
|
592
|
return ret
|
566
|
593
|
|
567
|
594
|
def __repr__(self):
|
568
|
|
- ret = "<LeGetQuery target={target_class} filter={query_filter} field_list={field_list} order={order} group={group} limit={limit} offset={offset}>"
|
|
595
|
+ ret = "<LeGetQuery target={target_class} filter={query_filter} \
|
|
596
|
+field_list={field_list} order={order} group={group} limit={limit} \
|
|
597
|
+offset={offset}>"
|
569
|
598
|
return ret.format(**self.dump_infos())
|
570
|
599
|
|