kongalib 2.0.5__cp314-cp314-macosx_10_15_universal2.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kongalib/expression.py ADDED
@@ -0,0 +1,841 @@
1
+ # -*- coding: utf-8 -*-
2
+ # _ _ _ _
3
+ # | | | (_) |
4
+ # | | _____ _ __ __ _ __ _| |_| |__
5
+ # | |/ / _ \| '_ \ / _` |/ _` | | | '_ \
6
+ # | < (_) | | | | (_| | (_| | | | |_) |
7
+ # |_|\_\___/|_| |_|\__, |\__,_|_|_|_.__/
8
+ # __/ |
9
+ # |___/
10
+ #
11
+ # Konga client library, by EasyByte Software
12
+ #
13
+ # https://github.com/easybyte-software/kongalib
14
+
15
+
16
+ from __future__ import print_function
17
+ from __future__ import absolute_import
18
+
19
+ import re
20
+ import io
21
+ import tempfile
22
+ import collections
23
+ from xml.etree import ElementTree as ET
24
+
25
+ from kongalib import ensure_text
26
+
27
+
28
+
29
+ class LRUCache(object):
30
+ def __init__(self, capacity, destructor=None):
31
+ self.capacity = capacity
32
+ self.destructor = destructor
33
+ self.cache = collections.OrderedDict()
34
+
35
+ def clear(self):
36
+ if self.destructor is not None:
37
+ for item in self.cache.items():
38
+ self.destructor(*item)
39
+ self.cache.clear()
40
+
41
+ def get(self, key, default=None):
42
+ try:
43
+ value = self.cache.pop(key)
44
+ self.cache[key] = value
45
+ return value
46
+ except KeyError:
47
+ return default
48
+
49
+ def items(self):
50
+ return self.cache.items()
51
+
52
+ def values(self):
53
+ return self.cache.values()
54
+
55
+ def keys(self):
56
+ return self.cache.keys()
57
+
58
+ def __getitem__(self, key):
59
+ value = self.cache.pop(key)
60
+ self.cache[key] = value
61
+ return value
62
+
63
+ def __setitem__(self, key, value):
64
+ try:
65
+ old_value = self.cache.pop(key)
66
+ if (value is not old_value) and (self.destructor is not None):
67
+ self.destructor(key, old_value)
68
+ except KeyError:
69
+ if len(self.cache) >= self.capacity:
70
+ item = self.cache.popitem(last=False)
71
+ if self.destructor is not None:
72
+ self.destructor(*item)
73
+ self.cache[key] = value
74
+
75
+ def __delitem__(self, key):
76
+ value = self.cache.pop(key)
77
+ if self.destructor is not None:
78
+ self.destructor(key, value)
79
+
80
+ def __contains__(self, key):
81
+ return key in self.cache
82
+
83
+ def __len__(self):
84
+ return len(self.cache)
85
+
86
+
87
+
88
+ _sParseCache = LRUCache(64)
89
+
90
+
91
+
92
+ def parse(sql):
93
+ if not sql:
94
+ return None
95
+ expr = _sParseCache.get(sql, None)
96
+ if expr is not None:
97
+ return expr
98
+
99
+ from . import lex, yacc
100
+
101
+ tokens = (
102
+ 'LPAREN',
103
+ 'RPAREN',
104
+ 'OPERAND',
105
+ 'ID',
106
+ 'VALUE',
107
+ 'AND',
108
+ 'OR',
109
+ 'NOT',
110
+ 'IS',
111
+ 'LIKE',
112
+ 'IN',
113
+ 'NULL',
114
+ 'COMMA',
115
+ )
116
+ reserved = set(('AND','OR','NOT','IS','LIKE','IN','NULL'))
117
+
118
+ t_COMMA = r'\,'
119
+ t_LPAREN = r'\('
120
+ t_RPAREN = r'\)'
121
+ t_OPERAND = r'\=|\<\=|\>\=|\<|\>|\!\=|\+|\-|\*|\/|\&|\||\^'
122
+ def t_ID(t):
123
+ r'[A-Za-z_][A-Za-z0-9_\.]*'
124
+ if t.value.upper() in reserved:
125
+ t.type = t.value.upper()
126
+ return t
127
+ def t_VALUE(t):
128
+ r'\"([^\"]*)\"|\'(\'\'|[^\'])*\'|(\-)?\d+'
129
+ c = t.value[0]
130
+ if (c == '"') or (c == "'"):
131
+ t.value = t.value[1:-1].replace("''", "'")
132
+ return t
133
+
134
+ def t_error(t):
135
+ print("Illegal character '%s'" % t.value[0])
136
+ t.lexer.skip(1)
137
+
138
+ t_ignore = ' \t'
139
+ lex.lex()
140
+
141
+ precedence = (
142
+ ( 'left', 'OR' ),
143
+ ( 'left', 'AND' ),
144
+ ( 'right', 'NOT' ),
145
+ )
146
+
147
+ def p_expression_and(p):
148
+ 'expression : expression AND expression'
149
+ p[0] = AND(p[1], p[3])
150
+
151
+ def p_expression_and_value(p):
152
+ 'expression : expression AND value'
153
+ try:
154
+ if eval(p[3]):
155
+ node = OperandEQ('1', '1')
156
+ else:
157
+ node = OperandNE('1', '1')
158
+ except:
159
+ node = OperandNE('1', '1')
160
+ p[0] = AND(p[1], node)
161
+
162
+ def p_value_and_expression(p):
163
+ 'expression : value AND expression'
164
+ try:
165
+ if eval(p[1]):
166
+ node = OperandEQ('1', '1')
167
+ else:
168
+ node = OperandNE('1', '1')
169
+ except:
170
+ node = OperandNE('1', '1')
171
+ p[0] = AND(node, p[3])
172
+
173
+ def p_expression_or(p):
174
+ 'expression : expression OR expression'
175
+ p[0] = OR(p[1], p[3])
176
+
177
+ def p_expression_or_value(p):
178
+ 'expression : expression OR value'
179
+ try:
180
+ if eval(p[3]):
181
+ node = OperandEQ('1', '1')
182
+ else:
183
+ node = OperandNE('1', '1')
184
+ except:
185
+ node = OperandNE('1', '1')
186
+ p[0] = OR(p[1], node)
187
+
188
+ def p_value_or_expression(p):
189
+ 'expression : value OR expression'
190
+ try:
191
+ if eval(p[1]):
192
+ node = OperandEQ('1', '1')
193
+ else:
194
+ node = OperandNE('1', '1')
195
+ except:
196
+ node = OperandNE('1', '1')
197
+ p[0] = OR(node, p[3])
198
+
199
+ def p_expression_fieldop(p):
200
+ 'expression : ID OPERAND ID'
201
+ p[0] = Operand(p[1], p[2], p[3], _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
202
+
203
+ def p_expression_binop(p):
204
+ 'expression : ID OPERAND VALUE'
205
+ p[0] = Operand(p[1], p[2], p[3])
206
+
207
+ def p_expression_valueop(p):
208
+ 'expression : VALUE OPERAND VALUE'
209
+ p[0] = Operand(p[1], p[2], p[3], _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
210
+
211
+ def p_expression_func_fieldop(p):
212
+ 'expression : function OPERAND ID'
213
+ p[0] = Operand(p[1], p[2], p[3], _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
214
+
215
+ def p_expression_func_binop(p):
216
+ 'expression : function OPERAND VALUE'
217
+ p[0] = Operand(p[1], p[2], p[3])
218
+
219
+ def p_expression_not(p):
220
+ 'expression : NOT expression'
221
+ p[0] = NOT(p[2])
222
+
223
+ def p_expression_paren(p):
224
+ 'expression : LPAREN expression RPAREN'
225
+ p[0] = p[2]
226
+
227
+ def p_expression_is_null(p):
228
+ 'expression : ID IS NULL'
229
+ p[0] = OperandIsNull(p[1])
230
+
231
+ def p_expression_is_not_null(p):
232
+ 'expression : ID IS NOT NULL'
233
+ p[0] = OperandIsNotNull(p[1])
234
+
235
+ def p_expression_like(p):
236
+ 'expression : ID LIKE VALUE'
237
+ p[0] = OperandLIKE(p[1], p[3])
238
+
239
+ def p_expression_not_like(p):
240
+ 'expression : ID NOT LIKE VALUE'
241
+ p[0] = OperandNotLIKE(p[1], p[4])
242
+
243
+ def p_expression_in(p):
244
+ 'expression : ID IN LPAREN valueslist RPAREN'
245
+ values = []
246
+ node = p[4]
247
+ while node is not None:
248
+ values.append(node[0])
249
+ node = node[1]
250
+ p[0] = OperandIN(p[1], values)
251
+
252
+ def p_expression_not_in(p):
253
+ 'expression : ID NOT IN LPAREN valueslist RPAREN'
254
+ values = []
255
+ node = p[5]
256
+ while node is not None:
257
+ values.append(node[0])
258
+ node = node[1]
259
+ p[0] = OperandNotIN(p[1], values)
260
+
261
+ def p_function(p):
262
+ 'function : ID LPAREN ID RPAREN'
263
+ p[0] = '%s(%s)' % (p[1], p[3])
264
+
265
+ def p_function_recursive(p):
266
+ 'function : ID LPAREN function RPAREN'
267
+ p[0] = '%s(%s)' % (p[1], p[3])
268
+
269
+ def p_value_paren(p):
270
+ 'value : LPAREN value RPAREN'
271
+ p[0] = p[2]
272
+
273
+ def p_value(p):
274
+ 'value : VALUE'
275
+ p[0] = p[1]
276
+
277
+ def p_valueslist_single(p):
278
+ 'valueslist : VALUE'
279
+ p[0] = (p[1], None)
280
+
281
+ def p_valueslist_multi(p):
282
+ 'valueslist : VALUE COMMA valueslist'
283
+ p[0] = (p[1], p[3])
284
+
285
+ def p_error(p):
286
+ if p:
287
+ raise SyntaxError("Parse error near '%s'" % p.value[0])
288
+ else:
289
+ raise SyntaxError("Parse error")
290
+
291
+ # yacc.yacc()
292
+ yacc.yacc(debug=False, outputdir=tempfile.gettempdir(), write_tables=False, errorlog=yacc.NullLogger())
293
+ expr = yacc.parse(sql, lexer=lex.lexer)
294
+ _sParseCache[sql] = expr
295
+ return expr
296
+
297
+
298
+
299
+ class _HasLogic(object):
300
+ LOGIC_NONE = 0
301
+ LOGIC_AND = 1
302
+ LOGIC_OR = 2
303
+ LOGIC_OP_MASK = ~0x3
304
+ LOGIC_NOT = 0x4
305
+
306
+ FLAG_NO_ESCAPE = 0x1
307
+ FLAG_VALUE_IS_FIELD = 0x2
308
+ FLAG_ESCAPE_LIKE = 0x4
309
+
310
+ def is_and(self):
311
+ return self.logic_op & _HasLogic.LOGIC_AND
312
+
313
+ def is_or(self):
314
+ return self.logic_op & _HasLogic.LOGIC_OR
315
+
316
+ def is_and_not(self):
317
+ if not (self.logic_op & _HasLogic.LOGIC_AND):
318
+ return False
319
+ children = self.parent.children
320
+ index = children.index(self)
321
+ if index + 1 >= len(children):
322
+ return False
323
+ return children[index + 1].logic_op & _HasLogic.LOGIC_NOT
324
+
325
+ def is_or_not(self):
326
+ if not (self.logic_op & _HasLogic.LOGIC_OR):
327
+ return False
328
+ children = self.parent.children
329
+ index = children.index(self)
330
+ if index + 1 >= len(children):
331
+ return False
332
+ return children[index + 1].logic_op & _HasLogic.LOGIC_NOT
333
+
334
+
335
+
336
+ class Operand(_HasLogic):
337
+ def __init__(self, column, operator, value, logic_op=_HasLogic.LOGIC_NONE, flags=0):
338
+ self.column = ensure_text(column)
339
+ self.operator = ensure_text(operator)
340
+ if value is not None:
341
+ self.value = ensure_text(value)
342
+ else:
343
+ self.value = None
344
+ self.logic_op = int(logic_op)
345
+ self.parent = None
346
+ self.flags = flags
347
+
348
+ def copy(self):
349
+ return Operand(self.column, self.operator, self.value, self.logic_op, self.flags)
350
+
351
+ def walk(self, repl):
352
+ repl(self)
353
+
354
+ def replace_markup(self, repl):
355
+ if self.value is not None:
356
+ if isinstance(repl, dict):
357
+ for key, value in repl.items():
358
+ self.value = self.value.replace(u'$%s' % key, ensure_text(value))
359
+ else:
360
+ self.value = repl(self.value)
361
+
362
+ def as_list(self):
363
+ return [ self.column, self.operator, self.value, self.flags ]
364
+
365
+ def __eq__(self, other):
366
+ return isinstance(other, Operand) and (self.column == other.column) and (self.operator == other.operator) and (self.value == other.value) and (self.logic_op == other.logic_op)
367
+
368
+ def __ne__(self, other):
369
+ return not self.__eq__(other)
370
+
371
+ def __hash__(self):
372
+ return hash(str(self))
373
+
374
+ def __str__(self):
375
+ if self.value is None:
376
+ value = 'NULL'
377
+ elif re.match(r'^(\-)?[0-9]+$', self.value):
378
+ value = self.value
379
+ else:
380
+ if self.operator in ('IN', 'NOT IN'):
381
+ value = self.value
382
+ else:
383
+ if self.flags & _HasLogic.FLAG_VALUE_IS_FIELD:
384
+ value = self.value
385
+ else:
386
+ value = "'%s'" % self.value.replace("'", "''")
387
+ return (u'%s %s %s' % (ensure_text(self.column), ensure_text(self.operator), ensure_text(value)))
388
+
389
+ def __repr__(self):
390
+ return str(self)
391
+
392
+ def apply(self, func):
393
+ func(self)
394
+
395
+ def serialize(self):
396
+ return {
397
+ '__type__': 'operand',
398
+ 'column': self.column,
399
+ 'op': self.operator,
400
+ 'logic_op': self.logic_op,
401
+ 'flags': self.flags,
402
+ 'value': ensure_text(self.value) if self.value is not None else None,
403
+ }
404
+
405
+ @classmethod
406
+ def unserialize(cls, obj):
407
+ if isinstance(obj, dict):
408
+ return Operand(obj['column'], obj['op'], obj['value'], obj['logic_op'], obj['flags'])
409
+ return obj
410
+
411
+ def serialize_xml(self, node):
412
+ """
413
+ Salva il descrittore sul nodo XML I{node}.
414
+
415
+ @param node: Nodo XML in cui salvare il descrittore.
416
+ @type node: ET.Element
417
+ """
418
+ node.attrib['column'] = self.column
419
+ node.attrib['operator'] = self.operator
420
+ if self.logic_op != _HasLogic.LOGIC_NONE:
421
+ node.attrib['logic_op'] = str(self.logic_op)
422
+ node.attrib['flags'] = str(self.flags)
423
+ if self.value is not None:
424
+ node.text = ensure_text(self.value)
425
+
426
+ @classmethod
427
+ def unserialize_xml(cls, node):
428
+ """
429
+ Carica ed instanzia un descrittore dal nodo XML I{node}.
430
+
431
+ @param node: Nodo XML da cui caricare la nuova istanza.
432
+ @type node: ET.Element
433
+
434
+ @return: Nuova istanza caricata dal nodo.
435
+ @rtype: L{ColumnDescriptor}
436
+ """
437
+ return Operand(node.get('column'), node.get('operator'), node.text, int(node.get('logic_op', _HasLogic.LOGIC_NONE)), int(node.get('flags', '0')))
438
+
439
+
440
+
441
+ class OperandEQ(Operand):
442
+ def __init__(self, column, value):
443
+ Operand.__init__(self, column, 'IS' if value is None else '=', value)
444
+
445
+
446
+
447
+ class OperandNE(Operand):
448
+ def __init__(self, column, value):
449
+ Operand.__init__(self, column, 'IS NOT' if value is None else '!=', value)
450
+
451
+
452
+
453
+ class OperandLT(Operand):
454
+ def __init__(self, column, value):
455
+ Operand.__init__(self, column, '<', value)
456
+
457
+
458
+
459
+ class OperandGT(Operand):
460
+ def __init__(self, column, value):
461
+ Operand.__init__(self, column, '>', value)
462
+
463
+
464
+
465
+ class OperandLE(Operand):
466
+ def __init__(self, column, value):
467
+ Operand.__init__(self, column, '<=', value)
468
+
469
+
470
+
471
+ class OperandGE(Operand):
472
+ def __init__(self, column, value):
473
+ Operand.__init__(self, column, '>=', value)
474
+
475
+
476
+
477
+ class OperandAND(Operand):
478
+ def __init__(self, column, value):
479
+ Operand.__init__(self, column, '&', value)
480
+
481
+
482
+
483
+ class OperandOR(Operand):
484
+ def __init__(self, column, value):
485
+ Operand.__init__(self, column, '|', value)
486
+
487
+
488
+
489
+ class OperandXOR(Operand):
490
+ def __init__(self, column, value):
491
+ Operand.__init__(self, column, '^', value)
492
+
493
+
494
+
495
+ class OperandLIKE(Operand):
496
+ def __init__(self, column, value):
497
+ Operand.__init__(self, column, 'LIKE', value)
498
+
499
+
500
+
501
+ class OperandNotLIKE(Operand):
502
+ def __init__(self, column, value):
503
+ Operand.__init__(self, column, 'NOT LIKE', value)
504
+
505
+
506
+
507
+ class OperandIsNull(Operand):
508
+ def __init__(self, column):
509
+ Operand.__init__(self, column, 'IS', None)
510
+
511
+
512
+
513
+ class OperandIsNotNull(Operand):
514
+ def __init__(self, column):
515
+ Operand.__init__(self, column, 'IS NOT', None)
516
+
517
+
518
+
519
+ class OperandIN(OperandNE):
520
+ def __init__(self, column, value):
521
+ if not isinstance(value, str):
522
+ value = u"('%s')" % (u"', '".join([ ensure_text(x).replace("'", "''") for x in value]))
523
+ Operand.__init__(self, column, 'IN', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
524
+
525
+
526
+
527
+ class OperandNotIN(OperandNE):
528
+ def __init__(self, column, value):
529
+ if not isinstance(value, str):
530
+ value = u"('%s')" % (u"', '".join([ ensure_text(x).replace("'", "''") for x in value]))
531
+ Operand.__init__(self, column, 'NOT IN', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE)
532
+
533
+
534
+
535
+ class OperandFieldEQ(OperandEQ):
536
+ def __init__(self, column, value):
537
+ Operand.__init__(self, column, '=', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
538
+
539
+
540
+
541
+ class OperandFieldNE(OperandNE):
542
+ def __init__(self, column, value):
543
+ Operand.__init__(self, column, '!=', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
544
+
545
+
546
+
547
+ class OperandFieldLT(OperandLT):
548
+ def __init__(self, column, value):
549
+ Operand.__init__(self, column, '<', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
550
+
551
+
552
+
553
+ class OperandFieldGT(OperandGT):
554
+ def __init__(self, column, value):
555
+ Operand.__init__(self, column, '>', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
556
+
557
+
558
+
559
+ class OperandFieldLE(OperandLE):
560
+ def __init__(self, column, value):
561
+ Operand.__init__(self, column, '<=', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
562
+
563
+
564
+
565
+ class OperandFieldGE(OperandGE):
566
+ def __init__(self, column, value):
567
+ Operand.__init__(self, column, '>=', value, _HasLogic.LOGIC_NONE, _HasLogic.FLAG_NO_ESCAPE | _HasLogic.FLAG_VALUE_IS_FIELD)
568
+
569
+
570
+
571
+ class Expression(_HasLogic):
572
+ def __init__(self, *args):
573
+ if len(args) == 0:
574
+ self.children = []
575
+ else:
576
+ for child in args:
577
+ if not isinstance(child, (Expression, Operand)):
578
+ raise ValueError('Expected Expression or Operand object')
579
+ self.children = args
580
+ self.name = None
581
+ self.logic_op = _HasLogic.LOGIC_NONE
582
+ self.parent = None
583
+
584
+ def set_name(self, name):
585
+ self.name = name
586
+
587
+ def get_name(self):
588
+ return self.name
589
+
590
+ def copy(self):
591
+ e = Expression()
592
+ e.name = self.name
593
+ e.logic_op = self.logic_op
594
+ for child in self.children:
595
+ e.children.append(child.copy())
596
+ child.parent = e
597
+ return e
598
+
599
+ def append(self, operand, logic_op):
600
+ operand.logic_op = (operand.logic_op & _HasLogic.LOGIC_OP_MASK) | logic_op
601
+ self.children.append(operand)
602
+ operand.parent = self
603
+
604
+ def walk(self, repl):
605
+ for child in self.children:
606
+ child.walk(repl)
607
+
608
+ def replace_markup(self, repl):
609
+ for child in self.children:
610
+ child.replace_markup(repl)
611
+
612
+ def as_list(self):
613
+ l = []
614
+ for index, child in enumerate(self.children):
615
+ if (index == 0) and (child.logic_op & _HasLogic.LOGIC_NOT):
616
+ l.append(True)
617
+ l.append(child.as_list())
618
+ if child is not self.children[-1]:
619
+ if child.logic_op & _HasLogic.LOGIC_AND:
620
+ op = 'AND'
621
+ elif child.logic_op & _HasLogic.LOGIC_OR:
622
+ op = 'OR'
623
+ if self.children[index + 1].logic_op & _HasLogic.LOGIC_NOT:
624
+ op += ' NOT'
625
+ else:
626
+ # if (len(self.children) == 1) and (self.children[-1].logic_op & _HasLogic.LOGIC_NOT):
627
+ # l[-1].append(True)
628
+ op = None
629
+ l.append(op)
630
+ return l
631
+
632
+ def __eq__(self, other):
633
+ if not isinstance(other, Expression):
634
+ return False
635
+ if len(self.children) != len(other.children):
636
+ return False
637
+ for child, other_child in zip(self.children, other.children):
638
+ if child != other_child:
639
+ return False
640
+ return True
641
+
642
+ def __ne__(self, other):
643
+ return not self.__eq__(other)
644
+
645
+ def __hash__(self):
646
+ return hash(str(self))
647
+
648
+ def __str__(self):
649
+ s = u''
650
+ for child in self.children:
651
+ if child.logic_op & _HasLogic.LOGIC_NOT:
652
+ s += 'NOT '
653
+ s += u'(%s)' % ensure_text(child)
654
+ if child is not self.children[-1]:
655
+ if child.logic_op & _HasLogic.LOGIC_AND:
656
+ s += ' AND '
657
+ elif child.logic_op & _HasLogic.LOGIC_OR:
658
+ s += ' OR '
659
+ return ensure_text(s)
660
+
661
+ def __repr__(self):
662
+ return str(self)
663
+
664
+ def __len__(self):
665
+ return len(self.children)
666
+
667
+ def __getitem__(self, index):
668
+ return self.children[index]
669
+
670
+ def apply(self, func):
671
+ for child in self.children:
672
+ child.apply(func)
673
+
674
+ def serialize(self):
675
+ obj = {
676
+ '__type__': 'expression',
677
+ 'name': self.name,
678
+ 'logic_op': self.logic_op,
679
+ 'children': []
680
+ }
681
+ for child in self.children:
682
+ obj['children'].append(child.serialize())
683
+ return obj
684
+
685
+ @classmethod
686
+ def unserialize(cls, obj):
687
+ if isinstance(obj, dict):
688
+ expr = Expression()
689
+ for child in obj['children']:
690
+ if isinstance(child, dict):
691
+ if child['__type__'] == 'expression':
692
+ elem = Expression.unserialize(child)
693
+ elif child['__type__'] == 'operand':
694
+ elem = Operand.unserialize(child)
695
+ else:
696
+ raise ValueError('Bad Expression JSON definition')
697
+ elif isinstance(child, (Operand, Expression)):
698
+ elem = child
699
+ else:
700
+ raise ValueError('Bad Expression XML definition')
701
+ expr.children.append(elem)
702
+ elem.parent = expr
703
+ expr.logic_op = obj['logic_op']
704
+ expr.name = obj['name']
705
+ return expr
706
+ return obj
707
+
708
+ def serialize_xml(self, node):
709
+ """
710
+ Salva il descrittore sul nodo XML I{node}.
711
+
712
+ @param node: Nodo XML in cui salvare il descrittore.
713
+ @type node: ET.Element
714
+ """
715
+ for child in self.children:
716
+ if isinstance(child, Operand):
717
+ elem = ET.SubElement(node, 'operand')
718
+ else:
719
+ elem = ET.SubElement(node, 'expression')
720
+ child.serialize_xml(elem)
721
+ if self.logic_op != _HasLogic.LOGIC_NONE:
722
+ node.attrib['logic_op'] = str(self.logic_op)
723
+ if self.name is not None:
724
+ node.attrib['name'] = self.name
725
+
726
+ @classmethod
727
+ def unserialize_xml(cls, node):
728
+ """
729
+ Carica ed instanzia un descrittore dal nodo XML I{node}.
730
+
731
+ @param node: Nodo XML da cui caricare la nuova istanza.
732
+ @type node: ET.Element
733
+
734
+ @return: Nuova istanza caricata dal nodo.
735
+ @rtype: L{ColumnDescriptor}
736
+ """
737
+ expr = Expression()
738
+ for child in node:
739
+ if ET.iselement(child):
740
+ if child.tag == 'expression':
741
+ elem = Expression.unserialize_xml(child)
742
+ elif child.tag == 'operand':
743
+ elem = Operand.unserialize_xml(child)
744
+ else:
745
+ raise ValueError('Bad Expression XML definition')
746
+ expr.children.append(elem)
747
+ elem.parent = expr
748
+ expr.logic_op = int(node.get('logic_op', _HasLogic.LOGIC_NONE))
749
+ expr.name = node.get('name', None)
750
+ return expr
751
+
752
+
753
+
754
+ def AND(*args):
755
+ args = [x for x in args if x is not None]
756
+ if len(args) == 1:
757
+ return args[0]
758
+ e = Expression()
759
+ for arg in args:
760
+ e.append(arg.copy(), _HasLogic.LOGIC_AND)
761
+ return e
762
+
763
+
764
+
765
+ def OR(*args):
766
+ args = [x for x in args if x is not None]
767
+ if len(args) == 1:
768
+ return args[0]
769
+ e = Expression()
770
+ for arg in args:
771
+ e.append(arg.copy(), _HasLogic.LOGIC_OR)
772
+ return e
773
+
774
+
775
+
776
+ def NOT(arg):
777
+ e = arg.copy()
778
+ e.logic_op ^= _HasLogic.LOGIC_NOT
779
+ return e
780
+
781
+
782
+
783
+ def where(expr):
784
+ if expr is None:
785
+ return []
786
+ elif isinstance(expr, str):
787
+ return where(parse(expr))
788
+ elif isinstance(expr, Operand):
789
+ return [ expr.as_list(), None ]
790
+ elif isinstance(expr, (tuple, list)):
791
+ return expr
792
+ else:
793
+ return expr.as_list()
794
+
795
+
796
+
797
+ def loads(xml):
798
+ if not xml:
799
+ return None
800
+ document = ET.ElementTree()
801
+ if isinstance(xml, str):
802
+ xml = ensure_text(xml).encode('utf-8')
803
+ if isinstance(xml, bytes):
804
+ xml = io.BytesIO(xml)
805
+ if not ET.iselement(xml):
806
+ xml = document.parse(xml, ET.XMLTreeBuilder(parse_comments=False))
807
+ if xml.tag == 'operand':
808
+ return Operand.unserialize_xml(xml)
809
+ elif xml.tag == 'expression':
810
+ return Expression.unserialize_xml(xml)
811
+ raise ValueError('expected valid expression XML')
812
+
813
+
814
+
815
+ def dumps(expr):
816
+ if expr is None:
817
+ return ''
818
+ elif isinstance(expr, Operand):
819
+ node = ET.Element('operand')
820
+ expr.serialize_xml(node)
821
+ return ET.tostring(node)
822
+ elif isinstance(expr, Expression):
823
+ node = ET.Element('expression')
824
+ expr.serialize_xml(node)
825
+ return ET.tostring(node)
826
+ raise ValueError('expected valid expression object')
827
+
828
+
829
+
830
+
831
+ # if __name__ == '__main__':
832
+ # sql = """(EB_Ciccio.a < 1) AND (EB_Pluto.b IN (0, 1, 2))"""
833
+ # # sql = """((EB_ClientiFornitori.Codice >= 'C00100') AND (EB_ClientiFornitori.Codice <= 'C00101')) AND ((EB_ClientiFornitori.ref_Azienda = 1) OR (EB_ClientiFornitori.ref_Azienda IS NULL)) AND (EB_ClientiFornitori.Tipo = 1)"""
834
+ # # sql = """(EB_Ciccio.a < 1) and (EB_Pluto.b != 'Antani')"""
835
+ # expr = parse(sql)
836
+ # print sql
837
+ # print expr.as_list()
838
+ # print type(expr)
839
+ # print expr
840
+
841
+