kongalib 2.0.4__cp314-cp314t-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.
Potentially problematic release.
This version of kongalib might be problematic. Click here for more details.
- _kongalib.cpython-314t-darwin.so +0 -0
- kongalib/__init__.py +394 -0
- kongalib/async_client.py +813 -0
- kongalib/client.py +1045 -0
- kongalib/constants.json +1 -0
- kongalib/constants.py +187 -0
- kongalib/data_dictionary.py +203 -0
- kongalib/db.py +267 -0
- kongalib/expression.py +841 -0
- kongalib/json.py +114 -0
- kongalib/lex.py +1058 -0
- kongalib/scripting.py +766 -0
- kongalib/yacc.py +3276 -0
- kongalib-2.0.4.dist-info/METADATA +150 -0
- kongalib-2.0.4.dist-info/RECORD +21 -0
- kongalib-2.0.4.dist-info/WHEEL +6 -0
- kongalib-2.0.4.dist-info/licenses/LICENSE +165 -0
- kongalib-2.0.4.dist-info/top_level.txt +4 -0
- kongalib-2.0.4.dist-info/zip-safe +1 -0
- kongaui.py +507 -0
- kongautil.py +581 -0
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
|
+
|