[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r7285 - trunk/gnue-common/src/datasources
From: |
johannes |
Subject: |
[gnue] r7285 - trunk/gnue-common/src/datasources |
Date: |
Fri, 1 Apr 2005 08:14:12 -0600 (CST) |
Author: johannes
Date: 2005-04-01 08:14:10 -0600 (Fri, 01 Apr 2005)
New Revision: 7285
Modified:
trunk/gnue-common/src/datasources/GConditions.py
trunk/gnue-common/src/datasources/GDataSource.py
Log:
Added asSQL () to GCondition, removed outdated functions and renamed
buildTreeFromList into buildConditionFromPrefix
Modified: trunk/gnue-common/src/datasources/GConditions.py
===================================================================
--- trunk/gnue-common/src/datasources/GConditions.py 2005-04-01 09:42:39 UTC
(rev 7284)
+++ trunk/gnue-common/src/datasources/GConditions.py 2005-04-01 14:14:10 UTC
(rev 7285)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common Library - Datasources - Conditions
#
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
#
+# This file is part of GNU Enterprise
+#
# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
@@ -16,20 +19,24 @@
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
-# Copyright 2000-2005 Free Software Foundation
-#
# $Id$
-#
from gnue.common.definitions.GObjects import GObj
from gnue.common.formatting import GTypecast
+from gnue.common.apps import errors
+
import mx.DateTime
import types
import string
import sys
import re
-class ConditionError (gException):
+
+# =============================================================================
+# Exceptions
+# =============================================================================
+
+class ConditionError (errors.ApplicationError):
pass
class ConditionNotSupported (ConditionError):
@@ -42,19 +49,19 @@
def __init__ (self, element, wanted):
msg = u_("Conditionelement '%(element)s' was expected to have '%(wanted)d'"
"arguments, but only has %(real)d'") \
- % {'element': element.__class__.split ('.') [-1],
+ % {'element': element._type,
'wanted' : wanted,
'real' : len (element._children)}
MalformedConditionTreeError.__init__ (self, msg)
class MissingFieldError (ConditionError):
- def __init__ (self, element):
+ def __init__ (self, field):
msg = u_("The field '%(field)s' has no entry in the given lookup-table") \
- % {'field': element.name }
+ % {'field': field }
ConditionError.__init__ (self, msg)
-class UnificationError (gException):
+class UnificationError (errors.ApplicationError):
pass
class ConversionRuleError (UnificationError):
@@ -75,9 +82,8 @@
UnificationError.__init__ (self, msg)
-
# =============================================================================
-# Base condition class; this is class is acts as root node of condition trees
+# Base condition class; this is class is the root node of condition trees
# =============================================================================
class GCondition (GObj):
@@ -85,35 +91,66 @@
A GCondition instance is allways the root node of a condition tree. All
children of a GCondition node are evaluated and combined using an AND
condition if not otherwise stated.
+
+ @ivar _maxChildren: if not None specifies the maximum number of children
+ allowed for a condition element.
+ @ivar _operator: unicode string defining the operator used for SQL
+ transformation of a condition element.
"""
- def __init__(self, parent = None, type = "GCCondition"):
+
+ # ---------------------------------------------------------------------------
+ # Create a new condition tree item
+ # ---------------------------------------------------------------------------
+
+ def __init__(self, parent = None, type = "GCCondition", prefixList = None):
+ """
+ @param parent: Parent instance in the GObj tree owning this instance
+ @param type: type of this instance (usually 'GCCondition')
+ @param prefixList: a condition in prefix notation; if this sequence is not
+ None, a condition tree according to this sequence will be built. This
+ instance is the root element of the newly created condition tree.
+ """
+
GObj.__init__ (self, parent, type = type)
self._maxChildren = None
+ self._operator = u''
+ if prefixList is not None:
+ self.buildFromList (prefixList)
+ self.validate ()
+
+
# ---------------------------------------------------------------------------
# Make sure an element of the tree has the requested number of children
# ---------------------------------------------------------------------------
- def _needChildren (self, number):
+ def _needChildren (self):
"""
- This function verifies if a condition element has a given number of
- children. If not an ArgumentCountError will be raised.
+ Ensure that the requested number of children is available.
+
+ @raise ArgumentCountError: raised if the number of children does not match
+ _maxChildren.
"""
- if number is not None and len (self._children) != number:
- raise ArgumentCountError, (self, number)
+ if self._maxChildren is not None and \
+ len (self._children) != self._maxChildren:
+ raise ArgumentCountError, (self, self._maxChildren)
+
# ---------------------------------------------------------------------------
# Evaluate a condition tree using the given lookup dictionary
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
"""
- This function evaluates the condition tree using the dictionary @lookup for
- retrieving field values. All children must evaluate to TRUE; evaluation
- stops on the first false result.
+ Evaluate a condition tree using a given lookup dictionary for field- and
+ parameter-values. Evaluation stops on the first False result.
+
+ @param lookup: dictionary used for lookups of field- and parameter-values.
+ @return: True or False
"""
+
self.validate ()
for child in self._children:
@@ -132,8 +169,9 @@
This function calls validate () on all it's children. Descendants might
override this function to do integrity checks and things like that.
"""
- self._needChildren (self._maxChildren)
+ self._needChildren ()
+
for child in self._children:
child.validate ()
@@ -147,6 +185,7 @@
This function returns the prefix notation of an element and all it's
children.
"""
+
result = []
append = result.extend
@@ -164,11 +203,42 @@
# Build an element and all it's children from a prefix notation list
# ---------------------------------------------------------------------------
+ def asSQL (self, paramDict):
+ """
+ Return the condition tree as SQL string in python-format using placeholders
+ and a given parameter dictionary.
+
+ Example:
+ condition = ['eq', ['field', 'foobar'], ['const', 'barbaz']]
+ result = condition.asSQL (pDict)
+
+ result = 'foobar = %(p0)s'
+ pDcit = {'p0': 'barbaz'}
+
+ @param paramDict: dictionary with all parameter values. this dictionary
+ will be populated with all placeholders used in the SQL string.
+
+ @return: SQL string representing the current condition
+ """
+
+ f = isinstance (self.getParent (), GConditionElement) and u'(%s)' or u'%s'
+ op = u' %s ' % self._operator
+ return f % op.join ([c.asSQL (paramDict) for c in self._children])
+
+
+ # ---------------------------------------------------------------------------
+ # Build an element and all it's children from a prefix notation list
+ # ---------------------------------------------------------------------------
+
def buildFromList (self, prefixList):
"""
This function creates a (partial) condition tree from a prefix notation
list.
+
+ @param prefixList: condition element sequence in prefix notation
+ @return: GCondition tree
"""
+
checktype (prefixList, types.ListType)
if len (prefixList):
@@ -207,7 +277,7 @@
reference cycles.
"""
- self._parent = None
+ self.setParent (None)
for item in self._children:
item.breakReferences ()
@@ -216,8 +286,8 @@
# Top level classes
# =============================================================================
-class GConditions(GCondition):
- def __init__(self, parent=None, type="GCConditions"):
+class GConditions (GCondition):
+ def __init__(self, parent = None, type = "GCConditions"):
GCondition.__init__(self, parent, type = type)
class GConditionElement (GCondition) :
@@ -241,9 +311,13 @@
def evaluate (self, lookup):
"""
- This function returns the fields value in the given lookup dictionary. If
- this dictionary has no key for the field a MissingFieldError will be
- raised.
+ Return the value of the field in the given lookup dictionary.
+
+ @param lookup: dictionary used for lookups
+ @return: value of the field
+
+ @raise MissingFieldError: raised if the lookup dictionary does not contain
+ a key for this field
"""
if not lookup.has_key (self.name):
raise MissingFieldError, (self.name)
@@ -259,7 +333,10 @@
"""
The prefix notation of a field element is a tuple of the identifier 'field'
(acting as operator) and the field's name.
+
+ @return: ['Field', name]
"""
+
return ['Field', self.name]
@@ -272,10 +349,26 @@
The single argument to a field 'operator' could be it's name, so this
method set's the fieldname.
"""
+
checktype (prefixList, [types.StringType, types.UnicodeType])
self.name = prefixList
+ # ---------------------------------------------------------------------------
+ # SQL represenation of a field is it's field name
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ The SQL representation of a field is it's name.
+
+ @param paramDict: current parameter dictionary
+ @return: the name of the field
+ """
+
+ return self.name
+
+
# -----------------------------------------------------------------------------
# A constant definition in a condition tree
# -----------------------------------------------------------------------------
@@ -294,7 +387,11 @@
def evaluate (self, lookup):
"""
This function returns the constants value
+
+ @param lookup: dictionary with lookup values
+ @return: value of the constant definition
"""
+
return self.value
@@ -306,6 +403,8 @@
"""
The prefix notation of a constant is a tuple of the identifier 'Const' and
the constant's value.
+
+ @return: ['Const', value]
"""
return ['Const', self.value]
@@ -318,10 +417,33 @@
"""
The single argument of a constant 'operator' could be it's value, so this
function set the constant's value.
+
+ @param prefixList: element sequence in prefix notation. For a constant
+ definition this sequence must be the constant's value.
"""
+
self.value = prefixList
+ # ---------------------------------------------------------------------------
+ # Return an SQL representation of a constant
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Add another key to the parameter dictionary holding the constant's value
+ and return an apropriate place holder for it.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: placeholder for the constant, i.e. '%(p0)s'
+ """
+
+ pKey = "p%d" % len (paramDict)
+ paramDict [pKey] = self.value
+
+ return u'%%(%s)s' % pKey
+
+
# -----------------------------------------------------------------------------
# Base class for parameter elements in a condition tree
# -----------------------------------------------------------------------------
@@ -340,6 +462,7 @@
"""
Descendants override this function to return the value of the parameter.
"""
+
return ""
@@ -350,7 +473,11 @@
def evaluate (self, lookup):
"""
A parameter element evaluates to it's value.
+
+ @param lookup: dictionary used for lookups
+ @return: the parameter's value
"""
+
return self.getValue ()
@@ -362,19 +489,58 @@
"""
The prefix notation of a parameter object is a 'constant' with the
parameters' value
+
+ @return: ['Const', value]
"""
return ['Const', self.getValue ()]
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of a parameter instance
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Add another key to the parameter dictionary holding the parameter's value
+ and return an apropriate place holder for it.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: placeholder for the parameter, i.e. '%(p0)s'
+ """
+
+ pKey = "p%d" % len (paramDict)
+ paramDict [pKey] = self.getValue ()
+ return u'%%(%s)s' % pKey
+
+
# =============================================================================
# Base classes for unary and binary operations
# =============================================================================
class GUnaryConditionElement (GConditionElement):
def __init__ (self, parent = None, elementType = ''):
- self._maxChildren = 1
GConditionElement.__init__ (self, parent, elementType)
+ self._maxChildren = 1
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of a unary operation
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Return a SQL code snippet for a unary operation.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: SQL code (in python-format) for the operation
+ """
+
+ return self._operator % self._children [0].asSQL (paramDict)
+
+
+# =============================================================================
+# Base class for binary operations
+# =============================================================================
+
class GBinaryConditionElement (GConditionElement):
def __init__ (self, parent = None, elementType = ''):
GConditionElement.__init__ (self, parent, elementType)
@@ -391,7 +557,8 @@
values in the property 'values'. Descendants can use these values for
further evaluations.
"""
- self._needChildren (self._maxChildren)
+
+ self._needChildren ()
self.values = unify ([child.evaluate (lookup) for child in self._children])
@@ -406,6 +573,7 @@
class GCand (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCand')
+ self._operator = 'AND'
# -----------------------------------------------------------------------------
@@ -415,6 +583,7 @@
class GCor (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCor')
+ self._operator = 'OR'
# ---------------------------------------------------------------------------
# Evaluate an OR tree
@@ -425,12 +594,14 @@
This function concatenates all children of this element by a logical OR.
The iteration stops on the first 'true' result.
"""
+
for child in self._children:
if child.evaluate (lookup):
return True
return False
+
# -----------------------------------------------------------------------------
# unary operation: NOT
# -----------------------------------------------------------------------------
@@ -438,6 +609,7 @@
class GCnot (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GCnot')
+ self._operator = 'NOT %s'
# ---------------------------------------------------------------------------
# logically Invert the childs result
@@ -447,7 +619,8 @@
"""
This function logically inverts the child's evaluation
"""
- self._needChildren (self._maxChildren)
+
+ self._needChildren ()
return not self._children [0].evaluate (lookup)
@@ -463,6 +636,7 @@
class GCadd (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCadd')
+ self._operator = '+'
# ---------------------------------------------------------------------------
# Evaluate the addition element
@@ -472,6 +646,7 @@
This function creates the sum of all it's children. A unify is used to
ensure all children evaluate to a numeric type.
"""
+
result = 0
for child in self._children:
result += unify ([child.evaluation (lookup), 0]) [0]
@@ -485,6 +660,7 @@
class GCsub (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCsub')
+ self._operator = '-'
# ---------------------------------------------------------------------------
# Evaluate the subtraction element
@@ -510,6 +686,7 @@
class GCmul (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCmul')
+ self._operator = '*'
# ---------------------------------------------------------------------------
# Evaluate the multiplication
@@ -535,7 +712,9 @@
class GCdiv (GConditionElement):
def __init__ (self, parent = None):
GConditionElement.__init__ (self, parent, 'GCdiv')
+ self._operator = '/'
+
# ---------------------------------------------------------------------------
# Evaluate the division element
# ---------------------------------------------------------------------------
@@ -552,6 +731,7 @@
return result
+
# -----------------------------------------------------------------------------
# unary operation: numeric negation
# -----------------------------------------------------------------------------
@@ -559,6 +739,7 @@
class GCnegate (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GCnegate')
+ self._operator = u"-%s"
# ---------------------------------------------------------------------------
# Evaluation of the numeric negation
@@ -568,7 +749,8 @@
"""
This function does a numeric negation on the child's evaluation result.
"""
- self._needChildren (self._maxChildren)
+
+ self._needChildren ()
return -unify ([self._children [0].evaluate (lookup), 0]) [0]
@@ -583,6 +765,7 @@
class GCeq (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCeq')
+ self._operator = u"="
# ---------------------------------------------------------------------------
# evaluate EQ relation
@@ -593,6 +776,27 @@
return self.values [0] == self.values [1]
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of an equal relation
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Return a SQL code snippet for this equal relation. If the right hand
+ element of the relation is a constant with a value of None, the operator
+ will be changed to the keyword 'IS'.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: SQL code for the condition element
+ """
+
+ if isinstance (self._children [1], GCConst) and \
+ self._children [1].value is None:
+ self._operator = u"IS"
+
+ return GBinaryConditionElement.asSQL (self, paramDict)
+
+
# -----------------------------------------------------------------------------
# Inequality
# -----------------------------------------------------------------------------
@@ -600,6 +804,7 @@
class GCne (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCne')
+ self._operator = u"!="
# ---------------------------------------------------------------------------
# evaluate NE relation
@@ -610,6 +815,27 @@
return self.values [0] != self.values [1]
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of an inequal relation
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Return a SQL code snippet for this inequal relation. If the right hand
+ element of the relation is a constant with a value of None, the operator
+ will be changed to the keyword 'IS NOT'.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: SQL code for the condition element
+ """
+
+ if isinstance (self._children [1], GCConst) and \
+ self._children [1].value is None:
+ self._operator = u"IS NOT"
+
+ return GBinaryConditionElement.asSQL (self, paramDict)
+
+
# -----------------------------------------------------------------------------
# Greater Than
# -----------------------------------------------------------------------------
@@ -617,6 +843,7 @@
class GCgt (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCgt')
+ self._operator = u">"
# ---------------------------------------------------------------------------
# evaluate GT relation
@@ -634,6 +861,7 @@
class GCge (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCge')
+ self._operator = u">="
# ---------------------------------------------------------------------------
# evaluate GE relation
@@ -644,7 +872,6 @@
return self.values [0] >= self.values [1]
-
# -----------------------------------------------------------------------------
# Less Than
# -----------------------------------------------------------------------------
@@ -652,6 +879,7 @@
class GClt (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GClt')
+ self._operator = u"<"
# ---------------------------------------------------------------------------
# evaluate LT relation
@@ -669,6 +897,7 @@
class GCle (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCle')
+ self._operator = u"<="
# ---------------------------------------------------------------------------
# evaluate LE relation
@@ -686,6 +915,7 @@
class GClike (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GClike')
+ self._operator = u"LIKE"
# ---------------------------------------------------------------------------
# Evaluate a like condition
@@ -711,6 +941,7 @@
class GCnotlike (GBinaryConditionElement):
def __init__ (self, parent = None):
GBinaryConditionElement.__init__ (self, parent, 'GCnotlike')
+ self._operator = u"NOT LIKE"
# ---------------------------------------------------------------------------
# Evaluate an inverted like condition
@@ -730,38 +961,74 @@
class GCbetween (GConditionElement):
def __init__ (self, parent = None):
- self._maxChildren = 3
GConditionElement.__init__ (self, parent, 'GCbetween')
+ self._maxChildren = 3
+ self._operator = u"BETWEEN"
# ---------------------------------------------------------------------------
# evaluate beetween relation
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
values = unify ([v.evaluate (lookup) for v in self._children])
return values [1] <= values [0] <= values [2]
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of a condition element
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Return a SQL code snippet for this condition element.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: SQL code for the condition element
+ """
+
+ f = isinstance (self.getParent (), GConditionElement) and u'(%s)' or u'%s'
+ return f % ('%s BETWEEN %s AND %s' \
+ % tuple ([item.asSQL (paramDict) for item in self._children]))
+
+
# -----------------------------------------------------------------------------
# Not Between
# -----------------------------------------------------------------------------
class GCnotbetween (GConditionElement):
def __init__ (self, parent = None):
- self._maxChildren = 3
GConditionElement.__init__ (self, parent, 'GCnotbetween')
+ self._maxChildren = 3
+ self._operator = u"NOT BETWEEN"
# ---------------------------------------------------------------------------
# evaluate an inverted beetween relation
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
values = unify ([v.evaluate (lookup) for v in self._children])
return not (values [1] <= values [0] <= values [2])
+ # ---------------------------------------------------------------------------
+ # Return a SQL representation of a condition element
+ # ---------------------------------------------------------------------------
+
+ def asSQL (self, paramDict):
+ """
+ Return a SQL code snippet for this condition element.
+
+ @param paramDict: parameter dictionary which will be extended
+ @return: SQL code for the condition element
+ """
+
+ f = isinstance (self.getParent (), GConditionElement) and u'(%s)' or u'%s'
+ return f % ('%s NOT BETWEEN %s AND %s' \
+ % tuple ([item.asSQL (paramDict) for item in self._children]))
+
+
# -----------------------------------------------------------------------------
# is NULL
# -----------------------------------------------------------------------------
@@ -769,13 +1036,14 @@
class GCnull (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GCnull')
+ self._operator = u"(%s IS NULL)"
# ---------------------------------------------------------------------------
# evaluate if a child is NULL
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
return self._children [0].evaluate (lookup) is None
@@ -786,13 +1054,14 @@
class GCnotnull (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GCnotnull')
+ self._operator = u"(%s IS NOT NULL)"
# ---------------------------------------------------------------------------
# evaluate if a child is not NULL
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
return self._children [0].evaluate (lookup) is not None
# -----------------------------------------------------------------------------
@@ -802,15 +1071,17 @@
class GCupper (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GCupper')
+ self._operator = u"UPPER (%s)"
# ---------------------------------------------------------------------------
# evaluate
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
return string.upper (self._children [0].evaluate (lookup))
+
# -----------------------------------------------------------------------------
# lower
# -----------------------------------------------------------------------------
@@ -818,16 +1089,19 @@
class GClower (GUnaryConditionElement):
def __init__ (self, parent = None):
GUnaryConditionElement.__init__ (self, parent, 'GClower')
+ self._operator = u"LOWER (%s)"
+
# ---------------------------------------------------------------------------
# evaluate
# ---------------------------------------------------------------------------
def evaluate (self, lookup):
- self._needChildren (self._maxChildren)
+ self._needChildren ()
return string.lower (self._children [0].evaluate (lookup))
+
# -----------------------------------------------------------------------------
# exist
# -----------------------------------------------------------------------------
@@ -866,7 +1140,22 @@
return result
+ # ---------------------------------------------------------------------------
+ # There's no exist for SQL atm, is it ?
+ # ---------------------------------------------------------------------------
+ def asSQL (self, paramDict):
+ """
+ Raise a NotImplementedError, since we do not support 'exist' elements in
+ SQL at the moment.
+
+ @raise NotImplementedError: whenever called for this condition element.
+ """
+
+ raise NotImplementedError
+
+
+
# =============================================================================
# Return a dictionary of all XML elements available
# =============================================================================
@@ -1033,26 +1322,65 @@
return xmlElements
+
+
###############################################################################
###############################################################################
#### Convenience Methods ##
###############################################################################
###############################################################################
-# =============================================================================
+
+# -----------------------------------------------------------------------------
+# Create a condition tree either from a prefix list or a dictionary
+# -----------------------------------------------------------------------------
+
+def buildCondition (condition, comparison = GCeq, logic = GCand):
+ """
+ Create a condition tree either from a sequence in prefix notation or a
+ dictionary. In the latter case an optional comparison- and logic-operator
+ class might be specified.
+
+ @param condition: sequence in prefix notation or a dictionary with the
+ condition to be converted
+ @param comparison: (operator) class used to compare keys and values
+ @param logic: (operator) class used to concatenate multiple comparisons
+
+ @return: GCondition tree
+ """
+
+ checktype (condition, [types.ListType, types.DictType, types.NoneType,
+ GCondition])
+
+ if isinstance (condition, types.ListType):
+ return GCondition (prefixList = condition)
+
+ elif isinstance (condition, types.DictType):
+ return buildConditionFromDict (condition, comparison, logic)
+
+ elif isinstance (condition, GCondition):
+ return condition
+
+ else:
+ return None
+
+
+# -----------------------------------------------------------------------------
# Create a condition tree from an element sequence in prefix notation
-# =============================================================================
+# -----------------------------------------------------------------------------
-def buildTreeFromList (prefixList):
+def buildConditionFromPrefix (prefixList):
"""
This function creates a new condition tree from the given element sequence,
which must be in prefix notation.
+
+ @param prefixList: sequence of condition elements in prefix notation
+ @return: GCondition tree
"""
+
checktype (prefixList, types.ListType)
- result = GCondition ()
- result.buildFromList (prefixList)
- return result
+ return GCondition (prefixList = prefixList)
# =============================================================================
@@ -1061,29 +1389,29 @@
def buildConditionFromDict (dictionary, comparison = GCeq, logic = GCand):
"""
- This function creates a new condition tree using @comparison as operation
- between keys and values and @logic as concatenation for all keys.
- """
- result = GCondition ()
- lastParent = result
+ This function creates a new condition tree using the given comparison as
+ operation between keys and values and a given logic as concatenation for all
+ keys.
- if len (dictionary.keys ()):
- lastParent = logic (lastParent)
+ @param dictionary: dictionary with (key, value) pairs to convert into a
+ condition tree
+ @param comparison: (operator) class used to compare keys and values
+ @param logic: (operator) class used to concatenate multiple comparisons
- for key, value in dictionary.items ():
- operation = comparison (lastParent)
- GCField (operation, key)
+ @return: GCondition tree
+ """
- if type (value) in [types.IntType, types.FloatType, types.LongType]:
- consttype = 'number'
- else:
- consttype = 'char'
+ checktype (dictionary, types.DictType)
- GCConst (operation, value, consttype)
+ c = comparison ()._type [2:]
+ pList = [[c, ['field', f], ['const', v]] for (f, v) in dictionary.items ()]
- return result
+ if pList:
+ pList.insert (0, logic ()._type [2:])
+ return GCondition (prefixList = pList)
+
# =============================================================================
# Combine two conditions with an AND clause. Side-effect: cond1 will be changed
# =============================================================================
@@ -1097,6 +1425,11 @@
neither of the conditions has a single top-level element of type GCand a new
element would be created.
"""
+
+ # TODO: replace this code with a cleaner implementation. Avoid that
+ # side-effect !!! But since we do *not* use weak references for GObj trees
+ # replacing this code with another one produces memory leaks
+
# check for the trivial cases
if cond1 is None or cond1 == {}:
return cond2
@@ -1144,7 +1477,7 @@
if update is not None:
for child in update._children:
- child._parent = update
+ child.setParent (update)
return cond1
@@ -1155,13 +1488,18 @@
def unify (values):
"""
- This function converts all values in the sequence @values to the same types
- pushing the results into the sequence @result.
+ Convert all items in a given sequence to the same types.
+
+ @param values: sequence of items to be converted to a common type
+ @return: sequence of converted items having all the same datatype.
"""
+
result = []
__unify (values, result)
+
return result
+
# -----------------------------------------------------------------------------
# Actual working method for unification
# -----------------------------------------------------------------------------
@@ -1323,369 +1661,5 @@
# Definition of an impossible condition
# =============================================================================
-GCimpossible = buildTreeFromList (['eq', ['const', 1], ['const', 2]])
+GCimpossible = GCondition (prefixList = ['eq', ['const', 1], ['const', 2]])
-
-
-###############################################################################
-###############################################################################
-#### Depreciated Methods ##
-###############################################################################
-###############################################################################
-
-#
-# a table with extra information about the different condition types
-# (needed for condition tree <-> prefix table conversion)
-#
-conditionElements = {
- 'add': (2, 999, GCadd ),
- 'sub': (2, 999, GCsub ),
- 'mul': (2, 999, GCmul ),
- 'div': (2, 999, GCdiv ),
- 'and': (1, 999, GCand ),
- 'or': (2, 999, GCor ),
- 'not': (1, 1, GCnot ),
- 'negate': (1, 1, GCnegate ),
- 'eq': (2, 2, GCeq ),
- 'ne': (2, 2, GCne ),
- 'gt': (2, 2, GCgt ),
- 'ge': (2, 2, GCge ),
- 'lt': (2, 2, GClt ),
- 'le': (2, 2, GCle ),
- 'like': (2, 2, GClike ),
- 'notlike': (2, 2, GCnotlike ),
- 'between': (3, 3, GCbetween ),
- 'null': (1, 1, GCnull),
- 'upper': (1, 1, GCupper),
- 'lower': (1, 1, GClower),
- }
-
-# creates an GCondition Tree out of an list of tokens in a prefix
-# order.
-
-def buildTreeFromPrefix(term):
-
- # create a GCondition object as top object in the object stack
- parent={0:(GCondition())}
-
- # GCondition will have only one parameter
- # add paramcount=1 to the parameter count stack
- paramcount={0:1}
-
- # set start level for stack to zero
- level=0
- for i in term:
-
- # convert type into an object
- if conditionElements.has_key(i[0]):
- e=conditionElements[i[0]][2](parent[level])
- level=level+1
- # get parameter count
- paramcount[level]=conditionElements[i[0]][0]
- parent[level]=e
- elif i[0]=="field":
- e=GCField(parent[level], i[1])
- paramcount[level]=paramcount[level]-1
- if paramcount[level]==0:
- level=level-1
- elif i[0]=="const":
- e=GCConst(parent[level], i[1])
- paramcount.update({level:(paramcount[level]-1)})
- if paramcount[level]==0:
- level=level-1
-# print "NAME: %s VALUE: %s LEVEL: %s PCOUNT: %s" % \
-# (i[0],i[1],level,paramcount[level])
-
- return parent[0];
-
-
-
-def buildPrefixFromTree(conditionTree):
- if type(conditionTree) != types.InstanceType:
- tmsg = u_("No valid condition tree")
- raise ConditionError, tmsg
- else:
- otype = string.lower(conditionTree._type[2:])
-
- #
- # care for objects without children
- #
- if otype == 'cfield':
- return [('field',"%s" % conditionTree.name)]
-
- elif otype == 'cconst':
- return [('const',conditionTree.value)]
-
- elif otype == 'cparam':
- return [('const', conditionTree.getValue())]
-
- #
- # if its an conditional object, then process it's children
- #
- elif conditionElements.has_key(otype):
- result=[]
-
- # first add operator to the list
- result.append((otype,'')); # ,None));
-
-
- # change operations with more than there minimal element no into
- # multiple operations with minimal elements
- # reason: to prevent a b c d AND OR being not well defined
- # because it can be a"a b c d AND AND OR" or "a b c d AND OR OR"
- paramcount=len(conditionTree._children)
- while (paramcount > \
- conditionElements[otype][0]):
- paramcount=paramcount-1
- result.append((otype,''));
-
-
- # then add children
- for i in range(0, len(conditionTree._children)):
- result = result + \
- buildPrefixFromTree(conditionTree._children[i])
-
- #
- # check for integrity of condition
- #
- if len(conditionTree._children) < conditionElements[otype][0]:
- tmsg = u_('Condition element "%(element)s" expects at most '
- '%(expected)s arguments; found %(found)s') \
- % {'element' : otype,
- 'expected': conditionElements[otype][0],
- 'found' : len (conditionTree._children)}
- raise ConditionError, tmsg
-
- if len(conditionTree._children) > conditionElements[otype][1]:
- tmsg = u_('Condition element "%(element)s" expects at most '
- '%(expected)s arguments; found %(found)s') \
- % {'element' : otype,
- 'expected': conditionElements[otype][1],
- 'found' : len (conditionTree._children)}
- raise ConditionError, tmsg
-
-
- # return combination
- return result;
-
- else:
- tmsg = u_('Condition clause "%s" is not supported '
- 'by the condition to prefix table conversion.') % otype
- raise ConditionNotSupported, tmsg
-
-#
-# Combine two conditions with an and clause.
-# NOTE: This modifies cond1 (and also returns it)
-#
-def __Original__combineConditions (cond1, cond2):
- if cond1 == None or cond1 == {}:
- return cond2
- elif cond2 == None or cond2 == {}:
- return cond1
-
- if type(cond1) == type({}):
- cond1 = buildConditionFromDict(cond1)
- if type(cond2) == type({}):
- cond2 = buildConditionFromDict(cond2)
-
- if not len(cond1._children):
- cond1._children = cond2._children
- return cond1
- elif len(cond2._children):
- children = cond1._children[:]
- cond1._children = []
- _and = GCand(cond1)
- _and._children = children
- if len(cond2._children) > 1:
- _and2 = GCand(cond1)
- _and2._children = cond2._children[:]
- else:
- cond1._children.append(cond2._children[0])
-
- return cond1
-
-
-
-# =============================================================================
-# Module self test code
-# =============================================================================
-
-if __name__ == '__main__':
- import sys
- from mx.DateTime import *
-
- # ---------------------------------------------------------------------------
- # self-test-function: unify two arguments
- # ---------------------------------------------------------------------------
-
- def _check_unify (values):
- args = string.join (["%s (%s)" % (v, type (v).__name__) for v in values])
- print "\nUnify:", args
-
- try:
- res = string.join (["%s (%s)" % (r, type (r).__name__) \
- for r in unify (values)])
- print " RES=", res
-
- except:
- print sys.exc_info () [0], sys.exc_info () [1]
-
-
- _check_unify ([u'17', 5])
- _check_unify ([5, '18'])
- _check_unify ([now (), '2004-08-15 14:00'])
- _check_unify (['13.0', 12])
- _check_unify (['15', ''])
- _check_unify ([7L, '12'])
- _check_unify ([7L, '12.2'])
- _check_unify ([1, 'True'])
- _check_unify ([])
- _check_unify ([1])
- _check_unify ([None])
- _check_unify (['5.43', 12, 18L])
- _check_unify ([None, 'foo'])
- _check_unify (['foo', None])
- _check_unify ([5, None, 2, None, '10'])
-
- print "unification sequence complete"
- raw_input ()
-
-
- # ---------------------------------------------------------------------------
- # Self-test-function: Construct conditions and evaluate them
- # ---------------------------------------------------------------------------
-
- def _check_construction (source, lookup):
- if isinstance (source, types.DictType):
- cond = buildConditionFromDict (source)
- else:
- cond = buildTreeFromList (source)
-
- print
- print "Source:", source
- print "Prefix:", cond.prefixNotation ()
- print "Lookup:", lookup
- print "Eval :", cond.evaluate (lookup)
-
-
- print "Condition tree transformation test"
-
- prefix = ['and', ['eq', ['field', u'foo'], ['const', 'bar']],
- ['ne', ['field', u'bar'], ['const', 'foobar']]]
-
- lookup = {'foo': 'bar',
- 'bar': 'foobarX'}
- _check_construction (prefix, lookup)
-
-
- prefix = ['or', ['between', ['field', u'foo'],
- ['const', 'bar'], ['const', 'char']],
- ['not', ['null', ['field', u'price']]]]
-
- lookup = {'foo': 'capo', 'price': None}
- _check_construction (prefix, lookup)
-
- prefix = ['like', ['field', u'foo'], ['const', 'bar%']]
- cond = buildTreeFromList (prefix)
- lookup = {'foo': 'Barrel'}
- _check_construction (prefix, lookup)
-
- lookup = {'foo': 'bar is running'}
- _check_construction (prefix, lookup)
-
- source = {'foo': 'bar', 'bar': 'trash'}
- lookup = {'foo': 'bar', 'bar': 'trash'}
- _check_construction (source, lookup)
-
- prefix = [['eq', ['field', 'foo'], ['const', 'bar']],
- ['lt', ['field', 'bar'], ['const', 10]]]
- lookup = {'foo': 'bar', 'bar': 5.6}
- _check_construction (prefix, lookup)
-
- prefix = ['eq', ['upper', ['field', 'nfoo']], ['upper', ['const', 'baR']]]
- lookup = {'nfoo': 'bAr'}
- _check_construction (prefix, lookup)
-
- prefix = ['eq', ['lower', ['field', 'nfoo']], ['const', 'bar']]
- lookup = {'nfoo': 'BaR'}
- _check_construction (prefix, lookup)
-
- print "end of construction test sequence"
- raw_input ()
-
- # ---------------------------------------------------------------------------
- # Self-test-function: Combine and evaluate condition trees
- # ---------------------------------------------------------------------------
-
- def _check_combineConditions (cond1, cond2):
- rc1 = cond1
- rc2 = cond2
- if not isinstance (cond1, types.DictType):
- rc1 = cond1.prefixNotation ()
- if not isinstance (cond2, types.DictType):
- rc2 = cond2.prefixNotation ()
-
- print "\nCombination of:"
- print " a:", rc1
- print " b:", rc2
- res = combineConditions (cond1, cond2)
- print " RES=", res.prefixNotation ()
-
-
- cond1 = GCondition ()
- cond2 = GCondition ()
-
- _check_combineConditions (cond1, cond2)
-
- prefix = ['eq', ['field', 'foo'], ['const', 'bar']]
- cond2 = buildTreeFromList (prefix)
-
- _check_combineConditions (cond1, cond2)
-
- cond1 = buildTreeFromList (prefix)
- cond2 = GCondition ()
- _check_combineConditions (cond1, cond2)
-
- prefix2 = ['and', ['null', ['field', 'nfoo']],
- ['notnull', ['field', 'nbar']]]
- cond2 = buildTreeFromList (prefix2)
- _check_combineConditions (cond1, cond2)
-
- cond1 = cond2
- cond2 = buildTreeFromList (prefix)
- _check_combineConditions (cond1, cond2)
-
- prefix3 = ['null', ['field', 'nfoo']]
- cond1 = buildTreeFromList (prefix)
- cond2 = buildTreeFromList (prefix3)
- _check_combineConditions (cond1, cond2)
-
- prefix4 = [['ne', ['field', 'foo'], ['const', 'bar']],
- ['lt', ['field', 'price'], ['const', 150.0]]]
- cond2 = buildTreeFromList (prefix4)
- _check_combineConditions (cond1, cond2)
-
- cond1 = buildTreeFromList (prefix)
- _check_combineConditions (cond2, cond1)
-
- prefix = ['or', ['null', ['field', 'nfoo']], ['eq', ['field', 'bar']]]
- prefix2 = ['or', ['notnull', ['field', 'nbar']], ['gt', ['field', 'foo']]]
- cond1 = buildTreeFromList (prefix)
- cond2 = buildTreeFromList (prefix2)
- _check_combineConditions (cond1, cond2)
-
- cond1 = buildTreeFromList (['and'])
- cond2 = buildTreeFromList (prefix)
- _check_combineConditions (cond1, cond2)
-
- print "start off"
- prefix = ['exist', 'customer', 'gnue_id', 'invoice.customer',
- ['or', ['null'], ['field', 'nfoo']]]
- cond = buildTreeFromList (prefix)
- for i in cond.findChildrenOfType ('GCexist', True, True):
- print i.table, i.masterlink, i.detaillink
- print "Children:"
- for c in i._children:
- print "C:", c.prefixNotation ()
-
- print "\n\nImpossible condition:", GCimpossible.prefixNotation ()
Modified: trunk/gnue-common/src/datasources/GDataSource.py
===================================================================
--- trunk/gnue-common/src/datasources/GDataSource.py 2005-04-01 09:42:39 UTC
(rev 7284)
+++ trunk/gnue-common/src/datasources/GDataSource.py 2005-04-01 14:14:10 UTC
(rev 7285)
@@ -999,7 +999,7 @@
['const', className]],
['eq', ['lower', ['field', 'gnue_module.gnue_name']],
['const', moduleName]]]
- mc = GConditions.buildTreeFromList (cond)
+ mc = GConditions.buildConditionFromPrefix (cond)
try:
rs = dts.createResultSet (mc)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r7285 - trunk/gnue-common/src/datasources,
johannes <=