commit-gnue
[Top][All Lists]
Advanced

[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)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]