[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
r5785 - in trunk: gnue-appserver/samples gnue-appserver/src gnue-appserv
From: |
johannes |
Subject: |
r5785 - in trunk: gnue-appserver/samples gnue-appserver/src gnue-appserver/src/classrep gnue-appserver/src/language gnue-common/src/datasources gnue-common/src/datasources/drivers/appserver/appserver gnue-common/src/schema/importer |
Date: |
Fri, 7 May 2004 04:11:23 -0500 (CDT) |
Author: johannes
Date: 2004-05-07 04:11:21 -0500 (Fri, 07 May 2004)
New Revision: 5785
Modified:
trunk/gnue-appserver/samples/sample.gfd
trunk/gnue-appserver/src/classrep/Base.py
trunk/gnue-appserver/src/classrep/Class.py
trunk/gnue-appserver/src/classrep/Module.py
trunk/gnue-appserver/src/classrep/Parameter.py
trunk/gnue-appserver/src/classrep/Procedure.py
trunk/gnue-appserver/src/classrep/Property.py
trunk/gnue-appserver/src/classrep/SchemaSupport.py
trunk/gnue-appserver/src/classrep/__init__.py
trunk/gnue-appserver/src/data.py
trunk/gnue-appserver/src/geasAuthentication.py
trunk/gnue-appserver/src/geasGsdGen.py
trunk/gnue-appserver/src/geasInstance.py
trunk/gnue-appserver/src/geasList.py
trunk/gnue-appserver/src/geasSession.py
trunk/gnue-appserver/src/geasSessionManager.py
trunk/gnue-appserver/src/language/ObjectList.py
trunk/gnue-common/src/datasources/GConditions.py
trunk/gnue-common/src/datasources/drivers/appserver/appserver/DataObject.py
trunk/gnue-common/src/schema/importer/Importer.py
Log:
GConditions are implemented a bit cleaner now :) Added prefix notation support,
and evaluation/validation of condition trees. Appserver now specifies
conditions in the prefix notation.
Modified: trunk/gnue-appserver/samples/sample.gfd
===================================================================
--- trunk/gnue-appserver/samples/sample.gfd 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/samples/sample.gfd 2004-05-07 09:11:21 UTC (rev
5785)
@@ -1,22 +1,32 @@
<?xml version="1.0" encoding="iso8859-1"?>
<form title="GNUe Application Server test">
- <parameter name="von" default="2270-07-15 09:00"/>
- <parameter name="bis" default="2270-09-15 20:00"/>
+ <parameter name="von" default="2270-05-20 09:00"/>
+ <parameter name="bis" default="2270-06-25 20:00"/>
<datasource name="dtsPerson" connection="appserver" table="address_person">
- <!--
<condition>
<and>
- <between>
- <cfield name="address_nextmeeting"/>
- <cparam name="von"/>
- <cparam name="bis"/>
- </between>
<or>
- <like>
- <cfield name="address_street"/>
- <cconst value="%street"/>
- </like>
+ <between>
+ <cfield name="address_nextmeeting"/>
+ <cparam name="von"/>
+ <cparam name="bis"/>
+ </between>
+ <null>
+ <cfield name="address_zip"/>
+ </null>
+ </or>
+
+ <ne>
+ <cfield name="address_name"/>
+ <cconst value="foo"/>
+ </ne>
+
+ <or>
+ <gt>
+ <cfield name="address_weight"/>
+ <cconst value="70"/>
+ </gt>
<or>
<eq>
<cfield name="address_zip"/>
@@ -28,13 +38,8 @@
</eq>
</or>
</or>
- <ne>
- <cfield name="address_name"/>
- <cconst value="foo"/>
- </ne>
</and>
</condition>
- -->
</datasource>
<datasource name="dtsCountry" connection="appserver" table="address_country"
cache="250"/>
Modified: trunk/gnue-appserver/src/classrep/Base.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Base.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/classrep/Base.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -303,7 +303,7 @@
self.classname = classname
self._session = session
- self.__object = aObject
+ self.__object = aObject
self.__predefined = {}
if pDefs is not None:
Modified: trunk/gnue-appserver/src/classrep/Class.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Class.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/classrep/Class.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -127,8 +127,8 @@
all classes of the bound module, otherwise no condition is given.
"""
if self.__module is not None:
- return [["eq", ""], ["field", u"gnue_module"],
- ["const", self.__module.gnue_id]]
+ return ['eq', ['field', u'gnue_module'],
+ ['const', self.__module.gnue_id]]
else:
return []
@@ -144,8 +144,8 @@
(moduleName, className) = splitName (key)
module = self.modules [moduleName]
- return [["eq", ""], ["field", u"gnue_module"], ["const", module.gnue_id],
- ["eq", ""], ["field", u"gnue_name"], ["const", className]]
+ return ['and', ['eq', ['field', u'gnue_module'], ['const',
module.gnue_id]],
+ ['eq', ['field', u'gnue_name'], ['const', classname]]]
# ---------------------------------------------------------------------------
@@ -180,7 +180,7 @@
# Wrapping a business object class
# ---------------------------------------------------------------------------
- def __init__ (self, session, classDict, module, object, predefs = None,
+ def __init__ (self, session, classDict, module, object, predefs = None,
propDefList = None):
BaseObject.__init__ (self, session, 'gnue_class', object, predefs)
@@ -213,8 +213,8 @@
Find a procedure @name.
"""
return self.procedures [name]
-
+
# ---------------------------------------------------------------------------
# Validate a class definition
# ---------------------------------------------------------------------------
@@ -226,7 +226,7 @@
except ValidationError:
del self.properties [p.fullName]
- gDebug (2, "%s.%s: %s: %s" % (self.fullName, p.fullName,
+ gDebug (2, "%s.%s: %s: %s" % (self.fullName, p.fullName,
sys.exc_info () [0], sys.exc_info () [1]))
for p in self.procedures.values ():
Modified: trunk/gnue-appserver/src/classrep/Module.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Module.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/classrep/Module.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -82,7 +82,7 @@
"""
Match a single module by it's name.
"""
- return [["eq", ""], ["field", "gnue_name"], ["const", key]]
+ return ['eq', ['field', u'gnue_name'], ['const', key]]
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/classrep/Parameter.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Parameter.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/classrep/Parameter.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -56,7 +56,7 @@
# ---------------------------------------------------------------------------
def _getNewItem (self, aObject):
- return Parameter (self._session, aObject,
+ return Parameter (self._session, aObject,
{"gnue_id": aObject.objectId})
@@ -65,8 +65,7 @@
# ---------------------------------------------------------------------------
def _getReloadCondition (self):
- return [["eq", ""], ["field", "gnue_procedure"],
- ["const", self.__proc.gnue_id]]
+ return ['eq', ['field', u'gnue_procedure'], ['const', self.__proc.gnue_id]]
# ---------------------------------------------------------------------------
@@ -74,9 +73,8 @@
# ---------------------------------------------------------------------------
def _getSingleCondition (self, key):
- res = self._getReloadCondition ()
- res.extend ([["eq", ""], ["field", "gnue_name"], ["const", key]])
- return res
+ return ['and', self._getReloadCondition (),
+ ['eq', ['field', u'gnue_name'], ['const', key]]]
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/classrep/Procedure.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Procedure.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/classrep/Procedure.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -71,7 +71,7 @@
# ---------------------------------------------------------------------------
def _getNewItem (self, aObject):
pMod = self.__module.modules.find (aObject.gnue_module.objectId)
- aProc = Procedure (self._session, pMod, aObject,
+ aProc = Procedure (self._session, pMod, aObject,
{"gnue_id": aObject.objectId})
aProc.parameters.reload ()
return aProc
@@ -81,8 +81,7 @@
# A reload () returns only the procedures of the class
# ---------------------------------------------------------------------------
def _getReloadCondition (self):
- return [["eq", ""], ["field", "gnue_class"],
- ["const", self.__class.gnue_id]]
+ return ['eq', ['field', u'gnue_class'], ['const', self.__class.gnue_id]]
# ---------------------------------------------------------------------------
@@ -91,9 +90,8 @@
def _getSingleCondition (self, key):
procName = splitName (key) [1]
- return [["eq", ""], ["field", "gnue_class"],
- ["const", self.__class.gnue_id],
- ["eq", ""], ["field", "gnue_name"], ["const", procName]]
+ return ['and', self._getReloadCondition (),
+ ['eq', ['field', u'gnue_name'], ['const', procName]]]
# ---------------------------------------------------------------------------
@@ -148,7 +146,7 @@
len (self.parameters.keys ()) == 0 and \
self.gnue_name [:3].lower () == 'get'
if self.isCalculated:
- self.calcFullName = createName (self.module.gnue_name,
+ self.calcFullName = createName (self.module.gnue_name,
self.gnue_name [3:])
else:
self.calcFullName = None
Modified: trunk/gnue-appserver/src/classrep/Property.py
===================================================================
--- trunk/gnue-appserver/src/classrep/Property.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/classrep/Property.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -72,7 +72,7 @@
# ---------------------------------------------------------------------------
def _getNewItem (self, aObject):
pMod = self.__module.modules.find (aObject.gnue_module.objectId)
- return Property (self._session, pMod, aObject,
+ return Property (self._session, pMod, aObject,
{"gnue_id": aObject.objectId})
@@ -80,8 +80,7 @@
# Restrict a reload () to the classes properties
# ---------------------------------------------------------------------------
def _getReloadCondition (self):
- return [["eq", ""], ["field", u"gnue_class"],
- ["const", self.__class.gnue_id]]
+ return ['eq', ['field', u'gnue_class'], ['const', self.__class.gnue_id]]
# ---------------------------------------------------------------------------
@@ -89,9 +88,8 @@
# ---------------------------------------------------------------------------
def _getSingleCondition (self, key):
propName = splitName (key) [1]
- return [["eq", ""], ["field", u"gnue_class"],
- ["const", self.__class.gnue_id],
- ["eq", ""], ["field", u"gnue_name"], ["const", propName]]
+ return ['and', self._getReloadCondition (),
+ ['eq', ['field', u'gnue_name'], ['const', propName]]]
# ---------------------------------------------------------------------------
@@ -223,7 +221,7 @@
referenced class definition.
"""
- res = helpers.verifyType (self.gnue_type, self.gnue_length,
+ res = helpers.verifyType (self.gnue_type, self.gnue_length,
self.gnue_scale, self.module.classes)
self.isReference = res is not None
self.referencedClass = res
Modified: trunk/gnue-appserver/src/classrep/SchemaSupport.py
===================================================================
--- trunk/gnue-appserver/src/classrep/SchemaSupport.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/classrep/SchemaSupport.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -161,7 +161,7 @@
xModules = [p.module.fullName for p in aClass.properties.values () + \
aClass.procedures.values ()]
for module in xModules:
- if module == 'gnue':
+ if module == 'gnue':
continue
if self.__exportModules.has_key (module):
self.__export (aClass, False, self.__exportModules.keys ())
Modified: trunk/gnue-appserver/src/classrep/__init__.py
===================================================================
--- trunk/gnue-appserver/src/classrep/__init__.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/classrep/__init__.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -40,7 +40,7 @@
try:
basedir = os.path.dirname
(sys.modules["gnue.appserver.classrep"].__file__)
except:
- basedir = os.path.dirname (__file__)
+ basedir = os.path.dirname (__file__)
if not os.path.isfile (os.path.join (basedir, "repository.ini")):
basedir = os.path.join (paths.data, "share", "gnue", "appserver")
Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py 2004-05-07 05:02:37 UTC (rev 5784)
+++ trunk/gnue-appserver/src/data.py 2004-05-07 09:11:21 UTC (rev 5785)
@@ -247,10 +247,9 @@
tables.append (table)
fields.extend (fieldlist)
if fk_alias:
- c = GConditions.buildTreeFromPrefix (
- [['eq', ''],
- ['field', alias + u'.gnue_id'],
- ['field', fk_alias + u'.' + fk_field]])
+ c = GConditions.buildTreeFromList (
+ ['eq', ['field', alias + u'.gnue_id'],
+ ['field', fk_alias + u'.' + fk_field]])
if conditions:
conditions = GConditions.combineConditions (conditions, c)
else:
@@ -826,8 +825,8 @@
print 'connection.query for previously inserted record ...',
content = {None: (u'address_person', None, None, [u'address_name'])}
rs = c.query (content,
- [['eq', ''], ['field', u'address_name'],
- ['const', u'New Person']], None)
+ ['eq', ['field', u'address_name'],
+ ['const', u'New Person']], None)
print 'Ok'
print 'recordset.firstRecord ...',
@@ -879,8 +878,8 @@
print 'check if the record is really gone now ...',
content = {None: (u'address_person', None, None, [u'address_name'])}
rs = c.query (content,
- [['eq', ''], ['field', u'address_city'],
- ['const', u'New City']],
+ ['eq', ['field', u'address_city'],
+ ['const', u'New City']],
None)
if rs.firstRecord () != None:
raise Exception
Modified: trunk/gnue-appserver/src/geasAuthentication.py
===================================================================
--- trunk/gnue-appserver/src/geasAuthentication.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/geasAuthentication.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -90,9 +90,7 @@
def authenticate (self, session, user, auth):
authList = self._intSess.request ("gnue_useraccess",
- [['eq', ''],
- ['field', 'gnue_username'],
- ['const', user ]],
+ ['eq', ['field', 'gnue_username'], ['const', user]],
[],
["gnue_username", "gnue_password",
"gnue_accesslist"])
Modified: trunk/gnue-appserver/src/geasGsdGen.py
===================================================================
--- trunk/gnue-appserver/src/geasGsdGen.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/geasGsdGen.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -27,7 +27,7 @@
from gnue.common.apps.GClientApp import *
from gnue.appserver import VERSION
-from gnue.appserver.geasSessionManager import geasSessionManager
+from gnue.appserver.geasSessionManager import geasSessionManager
from gnue.appserver.classrep.SchemaSupport import *
from gnue.appserver.classrep.Namespace import *
Modified: trunk/gnue-appserver/src/geasInstance.py
===================================================================
--- trunk/gnue-appserver/src/geasInstance.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/geasInstance.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -255,7 +255,7 @@
sess = Session.Session (self.__session.sm, self.__session.id)
# Create an object representing the current business object
- obj = Object.Object (sess, self.__classdef.fullName,
+ obj = Object.Object (sess, self.__classdef.fullName,
self.__getValue (u'gnue_id'))
# check the parameters
Modified: trunk/gnue-appserver/src/geasList.py
===================================================================
--- trunk/gnue-appserver/src/geasList.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/geasList.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -85,7 +85,7 @@
instance = geasInstance.geasInstance (self.__session, self.__connection,
record, self.__classdef)
if self.__condition is not None:
- if not self.__condition.eval (instance):
+ if not self.__condition.evaluate (instance):
return self.__getInstance ()
self.__instances.append (instance)
@@ -103,8 +103,11 @@
"""
This function returns the number of instances available in this list.
"""
- self.__fillup (0)
- return len (self.__instances)
+ if self.__condition is not None:
+ self.__fillup (0)
+ return len (self.__instances)
+ else:
+ return self.__recordset.count ()
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasSession.py
===================================================================
--- trunk/gnue-appserver/src/geasSession.py 2004-05-07 05:02:37 UTC (rev
5784)
+++ trunk/gnue-appserver/src/geasSession.py 2004-05-07 09:11:21 UTC (rev
5785)
@@ -216,7 +216,8 @@
if asCond is not None:
self.__addConditionToContent (classdef, content, asCond)
- self.__convertCondition (classdef, dsCond, content)
+ if dsCond is not None:
+ self.__convertCondition (classdef, dsCond, content)
sortlist = []
for p in sortorder:
@@ -375,8 +376,11 @@
by the datasource, and another one which has to be processed by appserver.
"""
+ if condition is None:
+ return (None, None)
+
if isinstance (condition, ListType):
- cTree = GConditions.buildTreeFromPrefix (condition)
+ cTree = GConditions.buildTreeFromList (condition)
else:
cTree = condition
@@ -386,7 +390,8 @@
if len (cTree._children):
# NOTE: the first element of a condition tree is a GCondition object
- self.__splitIntoAnd (cTree._children [0], forest)
+ # self.__splitIntoAnd (cTree._children [0], forest)
+ self.__splitIntoAnd (cTree, forest)
for tree in forest:
if self.__dbHandlesTree (tree, classdef):
@@ -402,19 +407,28 @@
# will do that later
if len (dbTrees):
dbCond = GConditions.GCondition ()
- comb = GConditions.GCand (dbCond)
- for tree in dbTrees:
- comb._children.append (tree)
- tree.parent = comb
+ if len (dbTrees) == 1:
+ dbCond._children.append (dbTrees [0])
+ dbTrees [0]._parent = dbCond
+ else:
+ comb = GConditions.GCand (dbCond)
+ for tree in dbTrees:
+ comb = GConditions.combineConditions (comb, tree)
+
if len (asTrees):
asCond = GConditions.GCondition ()
- comb = GConditions.GCand (asCond)
- for tree in asTrees:
- comb._children.append (tree)
- tree.parent = comb
+ if len (asTrees) == 1:
+ asCond._children.append (asTrees [0])
+ asTrees [0]._parent = asCond
+
+ else:
+ comb = GConditions.GCand (asCond)
+ for tree in asTrees:
+ comb = GConditions.combineConditions (comb, tree)
+
return (dbCond, asCond)
@@ -427,11 +441,15 @@
This function splits a condition tree into several independant subtrees
which can be re-combined via AND.
"""
- if isinstance (tree, GConditions.GCand):
+ if isinstance (tree, GConditions.GConditionElement):
+ if isinstance (tree, GConditions.GCand):
+ for child in tree._children:
+ self.__splitIntoAnd (child, forest)
+ else:
+ forest.append (tree)
+ else:
for child in tree._children:
self.__splitIntoAnd (child, forest)
- else:
- forest.append (tree)
# ---------------------------------------------------------------------------
Modified: trunk/gnue-appserver/src/geasSessionManager.py
===================================================================
--- trunk/gnue-appserver/src/geasSessionManager.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/geasSessionManager.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -48,7 +48,7 @@
# TODO: load default authagent depending on config setting
self._authAdapter = geasAuthentication.geasDBAuthAgent
(self._internalSession)
- self._langRuntimes = {}
+ self._langRuntimes = {}
# ---------------------------------------------------------------------------
# Build an internal session
Modified: trunk/gnue-appserver/src/language/ObjectList.py
===================================================================
--- trunk/gnue-appserver/src/language/ObjectList.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-appserver/src/language/ObjectList.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -80,7 +80,7 @@
sm = self.__session.getSessionManager ()
sid = self.__session.getSessionId ()
- self.__list_id = sm.request (sid, self.classname, self.conditions,
+ self.__list_id = sm.request (sid, self.classname, self.conditions,
self.sortOrder, self.properties)
self.__list = []
self.__populateList ()
Modified: trunk/gnue-common/src/datasources/GConditions.py
===================================================================
--- trunk/gnue-common/src/datasources/GConditions.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-common/src/datasources/GConditions.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -23,13 +23,16 @@
#
# DESCRIPTION:
#
-# $Id: $
+# $Id$
#
from gnue.common.definitions.GObjects import GObj
from gnue.common.formatting import GTypecast
import mx.DateTime
-import types, string
+import types
+import string
+import sys
+import re
class ConditionError (gException):
pass
@@ -77,49 +80,140 @@
UnificationError.__init__ (self, msg)
-class GCondition(GObj):
- def __init__(self, parent=None, type="GCCondition"):
- GObj.__init__(self, parent, type=type)
+# =============================================================================
+# Base condition class; this is class is acts as root node of condition trees
+# =============================================================================
+
+class GCondition (GObj):
+ """
+ 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.
+ """
+ def __init__(self, parent = None, type = "GCCondition"):
+ GObj.__init__ (self, parent, type = type)
+ self._maxChildren = None
+
+
# ---------------------------------------------------------------------------
+ # Make sure an element of the tree has the requested number of children
+ # ---------------------------------------------------------------------------
+
+ def _needChildren (self, number):
+ """
+ This function verifies if a condition element has a given number of
+ children. If not an ArgumentCountError will be raised.
+ """
+ if number is not None and len (self._children) != number:
+ raise ArgumentCountError, (self, number)
+
+
+ # ---------------------------------------------------------------------------
# Evaluate a condition tree using the given lookup dictionary
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+ def evaluate (self, lookup):
"""
This function evaluates the condition tree using the dictionary @lookup for
- retrieving field values.
+ retrieving field values. All children must evaluate to TRUE; evaluation
+ stops on the first false result.
"""
- self._needChildren (1)
- return self._children [0].eval (lookup)
+ self.validate ()
+ for child in self._children:
+ if not child.evaluate (lookup):
+ return False
+ return True
+
+
# ---------------------------------------------------------------------------
- # Make sure an element of the tree has the requested number of children
+ # Validate an element of a condition tree
# ---------------------------------------------------------------------------
- def _needChildren (self, number):
+ def validate (self):
"""
- This function verifies if a condition element has a given number of
- children. If not an ArgumentCountError will be raised.
+ This function calls validate () on all it's children. Descendants might
+ override this function to do integrity checks and things like that.
"""
- if len (self._children) != number:
- raise ArgumentCountError, (self, number)
+ self._needChildren (self._maxChildren)
+ for child in self._children:
+ child.validate ()
+ # ---------------------------------------------------------------------------
+ # Convert an element into prefix notation
+ # ---------------------------------------------------------------------------
+
+ def prefixNotation (self):
+ """
+ This function returns the prefix notation of an element and all it's
+ children.
+ """
+ result = []
+ append = result.extend
+
+ if isinstance (self, GConditionElement):
+ result.append (self._type [2:])
+ append = result.append
+
+ for child in self._children:
+ append (child.prefixNotation ())
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # 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.
+ """
+ checktype (prefixList, types.ListType)
+
+ if len (prefixList):
+ item = prefixList [0]
+
+ # be nice if there's a condition part missing
+ if isinstance (item, types.ListType):
+ self.buildFromList (item)
+ element = self
+ else:
+ # automatically map 'field' to 'Field' and 'const' to 'Const'
+ if item in ['field', 'const']:
+ item = item.title ()
+
+ element = getattr (sys.modules [__name__], "GC%s" % item) (self)
+
+ for subitem in prefixList [1:]:
+ element.buildFromList (subitem)
+
+
+# =============================================================================
+# Top level classes
+# =============================================================================
+
class GConditions(GCondition):
def __init__(self, parent=None, type="GCConditions"):
- GCondition.__init__(self, parent, type=type)
+ GCondition.__init__(self, parent, type = type)
class GConditionElement (GCondition) :
def __init__(self, parent=None, type="GConditionElement"):
- GCondition.__init__(self, parent, type=type)
+ GCondition.__init__ (self, parent, type = type)
+# -----------------------------------------------------------------------------
+# A Field element in the condition tree
+# -----------------------------------------------------------------------------
+
class GCField (GConditionElement):
- def __init__(self, parent, name=None, datatype="char"):
- GConditionElement.__init__(self, parent, 'GCCField')
+ def __init__(self, parent, name = None, datatype = "char"):
+ GConditionElement.__init__ (self, parent, 'GCCField')
self.type = datatype
self.name = name
@@ -127,7 +221,7 @@
# Evaluate a field element
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+ 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
@@ -139,304 +233,552 @@
return lookup [self.name]
+ # ---------------------------------------------------------------------------
+ # A field in prefix notation is a tuple of 'field' and fieldname
+ # ---------------------------------------------------------------------------
-class GCParam (GConditionElement):
- def __init__(self, parent, name=None, datatype="char"):
- GConditionElement.__init__(self, parent, 'GCCParam')
- self.type = datatype
- self.name = name
+ def prefixNotation (self):
+ """
+ The prefix notation of a field element is a tuple of the identifier 'field'
+ (acting as operator) and the field's name.
+ """
+ return ['Field', self.name]
- def getValue(self):
- return ""
- def eval (self, lookup):
- raise ConditionError, u_("Object can't evaluate!")
-
+ # ---------------------------------------------------------------------------
+ # to complete a field element from a prefix notation set the fieldname
+ # ---------------------------------------------------------------------------
+ def buildFromList (self, prefixList):
+ """
+ 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
+
+
+# -----------------------------------------------------------------------------
+# A constant definition in a condition tree
+# -----------------------------------------------------------------------------
+
class GCConst (GConditionElement):
- def __init__(self, parent, value=None, datatype="char"):
- GConditionElement.__init__(self, parent, 'GCCConst')
- self.type = datatype
+ def __init__ (self, parent, value = None, datatype = "char"):
+ GConditionElement.__init__ (self, parent, 'GCCConst')
+ self.type = datatype
self.value = value
+
# ---------------------------------------------------------------------------
# Evaluate a constant
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+ def evaluate (self, lookup):
"""
This function returns the constants value
"""
return self.value
-class GCadd(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCadd')
+ # ---------------------------------------------------------------------------
+ # The prefix notation of a constant is a tuple of identifier and value
+ # ---------------------------------------------------------------------------
- def eval (self, lookup):
+ def prefixNotation (self):
"""
- This function creates the sum of all it's children. A unify is used to
- ensure all children evaluate to a numeric type.
+ The prefix notation of a constant is a tuple of the identifier 'Const' and
+ the constant's value.
"""
- result = 0
- for child in self._children:
- values = []
- unify ([child.eval (lookup), 0], values)
- result += values [0]
- return result
+ return ['Const', self.value]
-class GCsub(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCsub')
+ # ---------------------------------------------------------------------------
+ # Recreate a constant from a prefix notation
+ # ---------------------------------------------------------------------------
-class GCmul(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCmul')
+ def buildFromList (self, prefixList):
+ """
+ The single argument of a constant 'operator' could be it's value, so this
+ function set the constant's value.
+ """
+ self.value = prefixList
-class GCdiv(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCdiv')
+# -----------------------------------------------------------------------------
+# Base class for parameter elements in a condition tree
+# -----------------------------------------------------------------------------
+class GCParam (GConditionElement):
+ def __init__ (self, parent, name = None, datatype = "char"):
+ GConditionElement.__init__ (self, parent, 'GCCParam')
+ self.type = datatype
+ self.name = name
-class GCand(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCand')
+ # ---------------------------------------------------------------------------
+ # Return the value of a parameter
+ # ---------------------------------------------------------------------------
+ def getValue(self):
+ """
+ Descendants override this function to return the value of the parameter.
+ """
+ return ""
+
+
# ---------------------------------------------------------------------------
- # Evaluate an 'AND' condition
+ # Evaluate the parameter object
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+ def evaluate (self, lookup):
"""
- This function concatenates all children of this element by a logical AND.
- The iteration stops on the first 'false' result.
+ A parameter element evaluates to it's value.
"""
- for child in self._children:
- if not child.eval (lookup):
- return False
+ return self.getValue ()
- return True
+ # ---------------------------------------------------------------------------
+ # Return a parameter object in prefix notation
+ # ---------------------------------------------------------------------------
-class GCor(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCor')
+ def prefixNotation (self):
+ """
+ The prefix notation of a parameter object is a 'constant' with the
+ parameters' value
+ """
+ return ['Const', self.getValue ()]
+
+# =============================================================================
+# Base classes for unary and binary operations
+# =============================================================================
+
+class GUnaryConditionElement (GConditionElement):
+ def __init__ (self, parent = None, elementType = ''):
+ self._maxChildren = 1
+ GConditionElement.__init__ (self, parent, elementType)
+
+class GBinaryConditionElement (GConditionElement):
+ def __init__ (self, parent = None, elementType = ''):
+ GConditionElement.__init__ (self, parent, elementType)
+ self._maxChildren = 2
+ self.values = []
+
# ---------------------------------------------------------------------------
+ # Evaluating a binary element means evaluation of both children
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ """
+ This function evaluates both children of a binary element storing their
+ values in the property 'values'. Descendants can use these values for
+ further evaluations.
+ """
+ self._needChildren (self._maxChildren)
+ self.values = unify ([child.evaluate (lookup) for child in self._children])
+
+
+# =============================================================================
+# Logical operators
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# n-ary operation: AND
+# -----------------------------------------------------------------------------
+
+class GCand (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCand')
+
+
+# -----------------------------------------------------------------------------
+# n-ary operation: OR
+# -----------------------------------------------------------------------------
+
+class GCor (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCor')
+
+ # ---------------------------------------------------------------------------
# Evaluate an OR tree
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+
+ def evaluate (self, lookup):
"""
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.eval (lookup):
+ if child.evaluate (lookup):
return True
return False
-
-class GCnot(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnot')
+# -----------------------------------------------------------------------------
+# unary operation: NOT
+# -----------------------------------------------------------------------------
+class GCnot (GUnaryConditionElement):
+ def __init__ (self, parent = None):
+ GUnaryConditionElement.__init__ (self, parent, 'GCnot')
+
# ---------------------------------------------------------------------------
- # Evaluate the element
+ # logically Invert the childs result
# ---------------------------------------------------------------------------
- def eval (self, lookup):
+ def evaluate (self, lookup):
"""
This function logically inverts the child's evaluation
"""
- self._needChildren (1)
- return not self._children [0].eval (lookup)
+ self._needChildren (self._maxChildren)
+ return not self._children [0].evaluate (lookup)
-class GCnegate(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnegate')
- def eval (self, lookup):
- self._needChildren (1)
- values = []
- unify ([self._children [0].eval (lookup), 0], values)
- return -values [0]
+# =============================================================================
+# Numeric operations
+# =============================================================================
+# ---------------------------------------------------------------------------
+# n-ary operation: Addition
+# ---------------------------------------------------------------------------
-class GCeq(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCeq')
+class GCadd (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCadd')
# ---------------------------------------------------------------------------
+ # Evaluate the addition element
+ # ---------------------------------------------------------------------------
+ def evaluate (self, lookup):
+ """
+ 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]
+ return result
+
+
+# -----------------------------------------------------------------------------
+# n-ary operation: Subtraction
+# -----------------------------------------------------------------------------
+
+class GCsub (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCsub')
+
+ # ---------------------------------------------------------------------------
+ # Evaluate the subtraction element
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ result = None
+
+ for child in self._children:
+ value = unify ([child.evaluation (lookup), 0]) [0]
+ if result is None:
+ result = value
+ else:
+ result -= value
+
+ return result
+
+
+# -----------------------------------------------------------------------------
+# n-ary operation: Multiplication
+# -----------------------------------------------------------------------------
+
+class GCmul (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCmul')
+
+ # ---------------------------------------------------------------------------
+ # Evaluate the multiplication
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ result = None
+
+ for child in self._children:
+ value = unify ([child.evaluate (lookup), 0]) [0]
+ if result is None:
+ result = value
+ else:
+ result *= value
+
+ return result
+
+
+# -----------------------------------------------------------------------------
+# n-ary operation: Division
+# -----------------------------------------------------------------------------
+
+class GCdiv (GConditionElement):
+ def __init__ (self, parent = None):
+ GConditionElement.__init__ (self, parent, 'GCdiv')
+
+ # ---------------------------------------------------------------------------
+ # Evaluate the division element
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ result = None
+
+ for child in self._children:
+ value = unify ([child.evaluate (lookup), 0]) [0]
+ if result is None:
+ result = value
+ else:
+ result /= value
+
+ return result
+
+# -----------------------------------------------------------------------------
+# unary operation: numeric negation
+# -----------------------------------------------------------------------------
+
+class GCnegate (GUnaryConditionElement):
+ def __init__ (self, parent = None):
+ GUnaryConditionElement.__init__ (self, parent, 'GCnegate')
+
+ # ---------------------------------------------------------------------------
+ # Evaluation of the numeric negation
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ """
+ This function does a numeric negation on the child's evaluation result.
+ """
+ self._needChildren (self._maxChildren)
+ return -unify ([self._children [0].evaluate (lookup), 0]) [0]
+
+
+# =============================================================================
+# Relational operations
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# Equality
+# -----------------------------------------------------------------------------
+
+class GCeq (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCeq')
+
+ # ---------------------------------------------------------------------------
# evaluate EQ relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] == result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] == self.values [1]
-class GCne(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCne')
+# -----------------------------------------------------------------------------
+# Inequality
+# -----------------------------------------------------------------------------
+class GCne (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCne')
+
# ---------------------------------------------------------------------------
# evaluate NE relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] != result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] != self.values [1]
-class GCgt(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCgt')
+# -----------------------------------------------------------------------------
+# Greater Than
+# -----------------------------------------------------------------------------
+class GCgt (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCgt')
+
# ---------------------------------------------------------------------------
# evaluate GT relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] > result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] > self.values [1]
+# -----------------------------------------------------------------------------
+# Greater or Equal
+# -----------------------------------------------------------------------------
-class GCge(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCge')
+class GCge (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCge')
# ---------------------------------------------------------------------------
- # evaluate NE relation
+ # evaluate GE relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] >= result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] >= self.values [1]
-class GClt(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GClt')
+# -----------------------------------------------------------------------------
+# Less Than
+# -----------------------------------------------------------------------------
+class GClt (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GClt')
+
# ---------------------------------------------------------------------------
# evaluate LT relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] < result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] < self.values [1]
+# -----------------------------------------------------------------------------
+# Less or Equal
+# -----------------------------------------------------------------------------
-class GCle(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCle')
+class GCle (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCle')
# ---------------------------------------------------------------------------
# evaluate LE relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (2)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [0] <= result [1]
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ return self.values [0] <= self.values [1]
+# -----------------------------------------------------------------------------
+# Like
+# -----------------------------------------------------------------------------
-class GClike(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GClike')
+class GClike (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GClike')
- def eval (self, lookup):
- self._needChildren (2)
- return True
+ # ---------------------------------------------------------------------------
+ # Evaluate a like condition
+ # ---------------------------------------------------------------------------
-class GCnotlike(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnotlike')
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ strpat = "^%s" % self.values [1]
+ strpat = strpat.replace ('?', '.').replace ('%', '.*')
+ pattern = re.compile (strpat)
+ return pattern.match (self.values [0]) is not None
- def eval (self, lookup):
- self._needChildren (2)
- return True
+# -----------------------------------------------------------------------------
+# Not Like
+# -----------------------------------------------------------------------------
-class GCbetween(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCbetween')
+class GCnotlike (GBinaryConditionElement):
+ def __init__ (self, parent = None):
+ GBinaryConditionElement.__init__ (self, parent, 'GCnotlike')
# ---------------------------------------------------------------------------
+ # Evaluate an inverted like condition
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ GBinaryConditionElement.evaluate (self, lookup)
+ strpat = "^%s" % self.values [1]
+ strpat = strpat.replace ('?', '.').replace ('%', '.*')
+ pattern = re.compile (strpat)
+ return pattern.match (self.values [0]) is None
+
+
+# -----------------------------------------------------------------------------
+# Between
+# -----------------------------------------------------------------------------
+
+class GCbetween (GConditionElement):
+ def __init__ (self, parent = None):
+ self._maxChildren = 3
+ GConditionElement.__init__ (self, parent, 'GCbetween')
+
+ # ---------------------------------------------------------------------------
# evaluate beetween relation
# ---------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (3)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return result [1] <= result [0] <= result [2]
+ def evaluate (self, lookup):
+ self._needChildren (self._maxChildren)
+ values = unify ([v.evaluate (lookup) for v in self._children])
+ return values [1] <= values [0] <= values [2]
-class GCnotbetween(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnotbetween')
+# -----------------------------------------------------------------------------
+# Not Between
+# -----------------------------------------------------------------------------
- def eval (self, lookup):
- self._needChildren (3)
- result = []
- unify ([v.eval (lookup) for v in self._children], result)
- return not (result [1] <= result [0] <= result [2])
+class GCnotbetween (GConditionElement):
+ def __init__ (self, parent = None):
+ self._maxChildren = 3
+ GConditionElement.__init__ (self, parent, 'GCnotbetween')
+ # ---------------------------------------------------------------------------
+ # evaluate an inverted beetween relation
+ # ---------------------------------------------------------------------------
-class GCnull(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnull')
+ def evaluate (self, lookup):
+ self._needChildren (self._maxChildren)
+ values = unify ([v.evaluate (lookup) for v in self._children])
+ return not (values [1] <= values [0] <= values [2])
- def eval (self, lookup):
- self._needChildren (1)
- return self._children [0].eval (lookup) is None
+# -----------------------------------------------------------------------------
+# is NULL
+# -----------------------------------------------------------------------------
-class GCnotnull(GConditionElement):
- def __init__(self, parent=None):
- GConditionElement.__init__(self, parent, 'GCnotnull')
+class GCnull (GUnaryConditionElement):
+ def __init__ (self, parent = None):
+ GUnaryConditionElement.__init__ (self, parent, 'GCnull')
- def eval (self, lookup):
- self._needChildren (1)
- return not self._children [0].eval (lookup) is None
+ # ---------------------------------------------------------------------------
+ # evaluate if a child is NULL
+ # ---------------------------------------------------------------------------
+ def evaluate (self, lookup):
+ self._needChildren (self._maxChildren)
+ return self._children [0].evaluate (lookup) is None
-# build an impossible condition GCondition={0=1}
-GCimpossible=GCondition()
-_h=GCeq(GCimpossible)
-GCConst(_h,1)
-GCConst(_h,2)
+# -----------------------------------------------------------------------------
+# is Not NULL
+# -----------------------------------------------------------------------------
+class GCnotnull (GUnaryConditionElement):
+ def __init__ (self, parent = None):
+ GUnaryConditionElement.__init__ (self, parent, 'GCnotnull')
-def getXMLelements(updates={}):
+ # ---------------------------------------------------------------------------
+ # evaluate if a child is not NULL
+ # ---------------------------------------------------------------------------
+
+ def evaluate (self, lookup):
+ self._needChildren (self._maxChildren)
+ return self._children [0].evaluate (lookup) is not None
+
+
+# =============================================================================
+# Return a dictionary of all XML elements available
+# =============================================================================
+
+def getXMLelements (updates = {}):
xmlElements = {
-## 'conditions': {
-## 'BaseClass': GConditions,
-## 'SingleInstance': 1,
-## 'ParentTags': None },
-
'conditions': {
'BaseClass': GCondition,
'ParentTags': ('conditions','and','or','not','negate'),
@@ -543,213 +885,143 @@
return xmlElements
+###############################################################################
+###############################################################################
+#### Convenience 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)
- }
+# =============================================================================
+# Create a condition tree from an element sequence in prefix notation
+# =============================================================================
+def buildTreeFromList (prefixList):
+ """
+ This function creates a new condition tree from the given element sequence,
+ which must be in prefix notation.
+ """
+ checktype (prefixList, types.ListType)
-#############################################################################
-#############################################################################
-#### Convenience Methods ##
-#############################################################################
-#############################################################################
+ result = GCondition ()
+ result.buildFromList (prefixList)
+ return result
-#
-# Build a condition tree using a dict
-# as a source. Assumes keys are field
-# names and values are constants.
-#
-def buildConditionFromDict (dict, comparison=GCeq, logic=GCand):
- cond = GCondition()
- lastParent = cond
+# =============================================================================
+# Create a condition tree from a dictionary
+# =============================================================================
- if len(dict.keys()):
- lastParent = logic(lastParent)
+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
- for key in dict.keys():
- eq = comparison(lastParent)
- GCField(eq, key)
+ if len (dictionary.keys ()):
+ lastParent = logic (lastParent)
-## if string.split(str(type(dict[key])),"'")[1] in ('int', 'float'):
- if type(dict[key]) in (types.IntType, types.FloatType):
- consttype="number"
+ for key, value in dictionary.items ():
+ operation = comparison (lastParent)
+ GCField (operation, key)
+
+ if type (value) in [types.IntType, types.FloatType, types.LongType]:
+ consttype = 'number'
else:
- consttype="char"
- GCConst(eq, dict[key], consttype)
+ consttype = 'char'
- return cond
+ GCConst (operation, value, consttype)
-#
-# Combine two conditions with an and clause.
-# NOTE: This modifies cond1 (and also returns it)
-#
+ return result
+
+
+# =============================================================================
+# Combine two conditions with an AND clause. Side-effect: cond1 will be changed
+# =============================================================================
+
def combineConditions (cond1, cond2):
- if cond1 == None or cond1 == {}:
+ """
+ This function combines the two condition trees @cond1 and @cond2 using an AND
+ clause. Both arguments can be given as conditiontrees or as dictionaries. In
+ the latter case they would be converted using buildConditionFromDict (). As a
+ side effect of this function, @cond1 would be changed (if neccessary). If
+ neither of the conditions has a single top-level element of type GCand a new
+ element would be created.
+ """
+ # check for the trivial cases
+ if cond1 is 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
+ elif cond2 is None or cond2 == {}:
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
+ # make sure both parts are condition trees
+ if isinstance (cond1, types.DictType):
+ cond1 = buildConditionFromDict (cond1)
+ if isinstance (cond2, types.DictType):
+ cond2 = buildConditionFromDict (cond2)
-# creates an GCondition Tree out of an list of tokens in a prefix
-# order.
+ # if the master condition has no elements, assign the second condition's
+ # children
+ if not len (cond1._children):
+ cond1._children = cond2._children
+ update = cond1
-def buildTreeFromPrefix(term):
+ elif len (cond2._children):
+ # First normalize the master condition. This means we make sure to have a
+ # valid logical operator as single top element
+ if len (cond1._children) > 1 or not isinstance (cond1._children [0],
GCand):
+ oldChildren = cond1._children [:]
+ cond1._children = []
+ parent = GCand (cond1)
+ parent._children = oldChildren
- # create a GCondition object as top object in the object stack
- parent={0:(GCondition())}
+ else:
+ parent = cond1._children [0]
- # GCondition will have only one parameter
- # add paramcount=1 to the parameter count stack
- paramcount={0:1}
+ # determine where to start in the second condition tree
+ buddy = cond2
+ while len (buddy._children) == 1 and \
+ isinstance (buddy._children [0], GCand):
+ buddy = buddy._children [0]
- # set start level for stack to zero
- level=0
- for i in term:
+ # and append all of the buddy's children to the top-level-and
+ parent._children.extend (buddy._children)
- # 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
+ update = parent
else:
- otype = string.lower(conditionTree._type[2:])
+ update = None
- #
- # care for objects without children
- #
- if otype == 'cfield':
- return [('field',"%s" % conditionTree.name)]
+ if update is not None:
+ for child in update._children:
+ child._parent = update
- elif otype == 'cconst':
- return [('const',conditionTree.value)]
+ return cond1
- 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 "%s" expects at least %s arguments; found
%s') % \
- (otype, conditionElements[otype][0],
len(conditionTree._children))
- raise ConditionError, tmsg
-
- if len(conditionTree._children) > conditionElements[otype][1]:
- tmsg = u_('Condition element "%s" expects at most %s arguments; found
%s') % \
- (otype, conditionElements[otype][1],
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
-
-
-# -----------------------------------------------------------------------------
+# =============================================================================
# Unify all elements in values to the same type
-# -----------------------------------------------------------------------------
+# =============================================================================
-def unify (values, result):
+def unify (values):
"""
This function converts all values in the sequence @values to the same types
pushing the results into the sequence @result.
"""
+ result = []
+ __unify (values, result)
+ return result
+# -----------------------------------------------------------------------------
+# Actual working method for unification
+# -----------------------------------------------------------------------------
+def __unify (values, result):
+ """
+ This function does the dirty work of 'unify ()'.
+ """
+
checktype (values, types.ListType)
if not len (values):
@@ -770,7 +1042,7 @@
if type (v1) == type (v2):
result.append (v1)
values.remove (v1)
- unify (values, result)
+ __unify (values, result)
else:
# String-Conversions
@@ -853,10 +1125,189 @@
raise ConversionRuleError, (v1, v2)
values [oldValue == v2] = newValue
- unify (values, result)
+ __unify (values, result)
# =============================================================================
+# Definition of an impossible condition
+# =============================================================================
+
+GCimpossible = buildTreeFromList (['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)
+ }
+
+# 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 "%s" expects at least %s arguments; found
%s') % \
+ (otype, conditionElements[otype][0],
len(conditionTree._children))
+ raise ConditionError, tmsg
+
+ if len(conditionTree._children) > conditionElements[otype][1]:
+ tmsg = u_('Condition element "%s" expects at most %s arguments; found
%s') % \
+ (otype, conditionElements[otype][1],
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
# =============================================================================
@@ -864,28 +1315,157 @@
import sys
from mx.DateTime import *
- def check (x, y):
- print "unify: %s (%s) vs %s (%s)" % (x, type (x), y, type (y))
- res = []
- vals = []
- if x != 0: vals.append (x)
- if y != 0: vals.append (y)
+ # ---------------------------------------------------------------------------
+ # 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:
- unify (vals, res)
- print "result:", ["%s (%s)" % (r, type (r).__name__) for r in res], "\n"
+ 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 (u'17', 5)
- check (5, '18')
- check (now (), '2004-08-15 14:00')
- check ('13.0', 12)
- check ('15', '')
- check (7L, '12')
- check (7L, '12.2')
- check (1, 'True')
- check (0, 0)
- check (1, 0)
- check (None, 0)
+
+ _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])
+
+ 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)
+
+ 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 "\n\nImpossible condition:", GCimpossible.prefixNotation ()
Property changes on: trunk/gnue-common/src/datasources/GConditions.py
___________________________________________________________________
Name: svn:keywords
- +svn:Id
+ Id
Modified:
trunk/gnue-common/src/datasources/drivers/appserver/appserver/DataObject.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/appserver/appserver/DataObject.py
2004-05-07 05:02:37 UTC (rev 5784)
+++ trunk/gnue-common/src/datasources/drivers/appserver/appserver/DataObject.py
2004-05-07 09:11:21 UTC (rev 5785)
@@ -53,7 +53,7 @@
else:
cond = conditions
- query = GConditions.buildPrefixFromTree (cond._children [0])
+ query = cond.prefixNotation ()
return query
Modified: trunk/gnue-common/src/schema/importer/Importer.py
===================================================================
--- trunk/gnue-common/src/schema/importer/Importer.py 2004-05-07 05:02:37 UTC
(rev 5784)
+++ trunk/gnue-common/src/schema/importer/Importer.py 2004-05-07 09:11:21 UTC
(rev 5785)
@@ -145,13 +145,12 @@
else:
fvalue = item.value
- cond.extend ([["eq", ""], ["field", fieldname],
- ["const", fvalue]])
+ cond.append (['eq', ['field', fieldname], ['const', fvalue]])
if len (cond) == 0:
raise ENoCondition (data.name, rowIndex)
- condition_tree = GConditions.buildTreeFromPrefix (cond)
+ condition_tree = GConditions.buildTreeFromList (cond)
resultset = datasource.createResultSet (condition_tree)
if resultset.firstRecord () is None:
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- r5785 - in trunk: gnue-appserver/samples gnue-appserver/src gnue-appserver/src/classrep gnue-appserver/src/language gnue-common/src/datasources gnue-common/src/datasources/drivers/appserver/appserver gnue-common/src/schema/importer,
johannes <=