commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r5196 - in trunk: gnue-appserver/src/classrep gnue-common/src/schema


From: johannes
Subject: r5196 - in trunk: gnue-appserver/src/classrep gnue-common/src/schema
Date: Sun, 29 Feb 2004 11:24:13 -0600 (CST)

Author: johannes
Date: 2004-02-29 11:24:11 -0600 (Sun, 29 Feb 2004)
New Revision: 5196

Modified:
   trunk/gnue-appserver/src/classrep/SchemaSupport.py
   trunk/gnue-common/src/schema/GSData.py
   trunk/gnue-common/src/schema/GSParser.py
   trunk/gnue-common/src/schema/Objects.py
Log:
Added a data-definition section to the gsd-files, making an explicit
type-argument in value-tags obsolet.


Modified: trunk/gnue-appserver/src/classrep/SchemaSupport.py
===================================================================
--- trunk/gnue-appserver/src/classrep/SchemaSupport.py  2004-02-29 00:34:46 UTC 
(rev 5195)
+++ trunk/gnue-appserver/src/classrep/SchemaSupport.py  2004-02-29 17:24:11 UTC 
(rev 5196)
@@ -182,32 +182,36 @@
     moddata = GSTableData (gsData)
     moddata.name      = 'gnue_module_dump'
     moddata.tablename = 'gnue_module'
+    self.__addColumnDefinition (moddata, 'gnue_module')
     modrows = GSRows (moddata)
 
     for moduledef in modules.values ():
       mProp = self.__classes ["gnue_module"].properties
       row   = GSRow (modrows)
 
-      self.__buildValue (row, mProp ["gnue_id"], moduledef.gnue_id)
-      self.__buildValue (row, mProp ["gnue_name"], moduledef.gnue_name)
+      self.__buildValue (row, mProp ["gnue_id"]     , moduledef.gnue_id)
+      self.__buildValue (row, mProp ["gnue_name"]   , moduledef.gnue_name)
       self.__buildValue (row, mProp ["gnue_comment"], moduledef.gnue_comment)
 
     # dump all gnue_class rows for the requested tables
     tabledata = GSTableData (gsData)
     tabledata.name      = 'gnue_class_dump'
     tabledata.tablename = 'gnue_class'
+    tableDef = self.__addColumnDefinition (tabledata, 'gnue_class')
     tablerows = GSRows (tabledata)
 
     # and all their properties
     propdata = GSTableData (gsData)
     propdata.name      = 'gnue_property_dump'
     propdata.tablename = 'gnue_property'
+    tableDef = self.__addColumnDefinition (propdata, 'gnue_property')
     proprows = GSRows (propdata)
 
     # and all their procedures
     procdata = GSTableData (gsData)
     procdata.name      = 'gnue_procedure_dump'
     procdata.tablename = 'gnue_procedure'
+    tableDef = self.__addColumnDefinition (procdata, 'gnue_procedure')
     procrows = GSRows (procdata)
 
     for classdef in classdefs:
@@ -216,9 +220,9 @@
       # save tabledata
       row = GSRow (tablerows)
 
-      self.__buildValue (row, cProp ["gnue_id"], classdef.gnue_id)
-      self.__buildValue (row, cProp ["gnue_module"], classdef.gnue_module)
-      self.__buildValue (row, cProp ["gnue_name"], classdef.gnue_name)
+      self.__buildValue (row, cProp ["gnue_id"]     , classdef.gnue_id)
+      self.__buildValue (row, cProp ["gnue_module"] , classdef.gnue_module)
+      self.__buildValue (row, cProp ["gnue_name"]   , classdef.gnue_name)
       self.__buildValue (row, cProp ["gnue_comment"], classdef.gnue_comment)
 
       for propdef in classdef.properties.values ():
@@ -226,13 +230,13 @@
         pProp = self.__classes ["gnue_property"].properties
         row = GSRow (proprows)
 
-        self.__buildValue (row, pProp ["gnue_id"], propdef.gnue_id)
-        self.__buildValue (row, pProp ["gnue_module"], propdef.gnue_module)
-        self.__buildValue (row, pProp ["gnue_class"], propdef.gnue_class)
-        self.__buildValue (row, pProp ["gnue_name"], propdef.gnue_name)
-        self.__buildValue (row, pProp ["gnue_type"], propdef.gnue_type)
-        self.__buildValue (row, pProp ["gnue_length"], propdef.gnue_length)
-        self.__buildValue (row, pProp ["gnue_scale"], propdef.gnue_scale)
+        self.__buildValue (row, pProp ["gnue_id"]     , propdef.gnue_id)
+        self.__buildValue (row, pProp ["gnue_module"] , propdef.gnue_module)
+        self.__buildValue (row, pProp ["gnue_class"]  , propdef.gnue_class)
+        self.__buildValue (row, pProp ["gnue_name"]   , propdef.gnue_name)
+        self.__buildValue (row, pProp ["gnue_type"]   , propdef.gnue_type)
+        self.__buildValue (row, pProp ["gnue_length"] , propdef.gnue_length)
+        self.__buildValue (row, pProp ["gnue_scale"]  , propdef.gnue_scale)
         self.__buildValue (row, pProp ["gnue_comment"], propdef.gnue_comment)
 
       for procdef in classdef.procedures.values ():
@@ -255,12 +259,27 @@
   def __buildValue (self, row, prop, data):
     value = GSValue (row)
     value.field = prop.column
-    value.type  = prop.dbFullType
     GContent (value,
       unicode (self.__nativeToString (data, prop.dbFullType), 'utf-8'))
 
 
   # ---------------------------------------------------------------------------
+  # Add a column definition section to the given tabledata for classname
+  # ---------------------------------------------------------------------------
+
+  def __addColumnDefinition (self, tableData, classname):
+    tableDef = GSDefinition (tableData)
+
+    classdef = self.__classes [classname]
+    for prop in classdef.properties.values ():
+      column = GSColumn (tableDef)
+      column.field = prop.column
+      column.type = prop.dbFullType
+
+    return tableDef
+
+
+  # ---------------------------------------------------------------------------
   # Convert a native python object to a string according to datatype
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-common/src/schema/GSData.py
===================================================================
--- trunk/gnue-common/src/schema/GSData.py      2004-02-29 00:34:46 UTC (rev 
5195)
+++ trunk/gnue-common/src/schema/GSData.py      2004-02-29 17:24:11 UTC (rev 
5196)
@@ -30,6 +30,9 @@
 # =============================================================================
 
 _LENGTH_SCALE = re.compile ('^\w+\s*\((\d+)[\.]{0,1}(\d*)\)\s*')
+_VALID_TYPES  = ["string", "number", "boolean", "date", "time", "datetime"]
+_TRANS_TYPES  = { "text": "string",
+                  "timestamp": "datetime" }
 
 
 # =============================================================================
@@ -190,12 +193,52 @@
 
 
 
+# -----------------------------------------------------------------------------
+# verify a given datatype
+# -----------------------------------------------------------------------------
 
+def verifyDataType (gsColumn):
+  """
+  This function checks if the @gsColumn instance has a vaild type attribute.
+  If the datatype is valid, this function creates a tuple of '(typename, 
lenght,
+  scale)', otherwise an EInvalidType exception will be raised.
+  """
+  fieldType = gsColumn.type.lower ().strip ()
+  tpMatch   = re.compile ('^(\w+)').match (fieldType)
+  tpList    = _VALID_TYPES + _TRANS_TYPES.keys ()
+
+  # check if we know the given type
+  if tpMatch is None or not tpMatch.groups () [0] in tpList:
+    raise EInvalidType (gsColumn, fieldType)
+
+  # and eventually translate it
+  typename = tpMatch.groups () [0]
+  if _TRANS_TYPES.has_key (typename):
+    typename = _TRANS_TYPES [typename]
+
+  flength = 0
+  fscale  = 0
+
+  # try to extract length and scale from fieldType
+  lsMatch = _LENGTH_SCALE.match (fieldType)
+  if lsMatch is not None:
+    (lstr, sstr) = lsMatch.groups ()
+
+    if len (lstr):
+      flength = int (lstr)
+    if len (sstr):
+      fscale  = int (sstr)
+
+  return (typename, flength, fscale)
+
+  
+
+
 # -----------------------------------------------------------------------------
 # Convert a value from a GSValue instance to a native python object
 # -----------------------------------------------------------------------------
 
-def valueToNative (gsValue):
+def valueToNative (gsValue, gsColumn):
   """
   This function takes a GSValue instance and creates a native python object
   representing it's value according to it's type. If the value is an empty
@@ -209,128 +252,107 @@
     gsValue.dataType = None
     return None
 
-  # if gsValue has no type information we assume it to be string
-  if not hasattr (gsValue, "type"):
-    gsValue.dataType = "string"
-    return fieldValue
+  # if we have a gsColumn instance supplied, we use it's datatype definition
+  if gsColumn is not None:
+    gsValue.dataType = gsColumn.typename
+    gsValue.length   = gsColumn.length
+    gsValue.scale    = gsColumn.scale
 
   else:
-    # extract the datatype first
-    ftm = re.compile ('^(\w+)').match (gsValue.type.lower ())
-    if ftm is None:
-      raise EInvalidType (gsValue, gsValue.type)
-
-    fieldType = ftm.groups () [0]
-
-    # default type is text (if no explicit type attribute is given)
-    if fieldType == "text":
-      fieldType = "string"
-
-    if fieldType == "timestamp":
-      fieldType = "datetime"
-
+    (fieldType, length, scale) = verifyDataType (gsValue)
     gsValue.dataType = fieldType
+    gsValue.length   = length
+    gsValue.scale    = scale
 
-    # a string type must stay in it's bounds (if known)
-    if fieldType == "string":
 
-      # if the fieldtype contains a length, we've to check it
-      if _LENGTH_SCALE.match (gsValue.type) is not None:
-        flen = int (_LENGTH_SCALE.match (gsValue.type).groups () [0])
+  # a string type must stay in it's bounds (if known)
+  if gsValue.dataType == "string":
+    if gsValue.length > 0 and len (fieldValue) > gsValue.length: 
+      raise EOutOfRange (gsValue, fieldValue, gsValue.length)
 
-        if len (fieldValue) > flen:
-          raise EOutOfRange (gsValue, fieldValue, flen)
+    return fieldValue
 
-      return fieldValue
+  # create a number according to length and scale
+  elif gsValue.dataType == "number":
+    value = fieldValue.strip ()
 
+    if gsValue.length or gsValue.scale:
+      vmatch = re.compile ('^([+-]{0,1})(\d+)[\.]{0,1}(\d*)$').match (value)
+      if vmatch is None:
+        raise EInvalidNumber (gsValue, value, gsValue.length, gsValue.scale)
 
-    # create a number according to length and scale
-    elif fieldType == "number":
-      value = fieldValue.strip ()
+      sign = vmatch.groups () [0]
+      pre  = vmatch.groups () [1]
+      frac = vmatch.groups () [2]
 
-      if _LENGTH_SCALE.match (gsValue.type) is not None:
-        fmatch = _LENGTH_SCALE.match (gsValue.type)
-        (fml, fms) = fmatch.groups ()
+      if len (pre) > (gsValue.length - gsValue.scale) or \
+         len (frac) > gsValue.scale:
+        raise EOutOfRange (gsValue, value, gsValue.length, gsValue.scale)
 
-        flength = int (fml)
-        fscale  = 0
-        if len (fms):
-          fscale = int (fms)
+      if len (frac):
+        return float ("%s%s.%s" % (sign, pre, frac))
 
-        vmatch = re.compile ('^([+-]{0,1})(\d+)[\.]{0,1}(\d*)$').match (value)
-        if vmatch is None:
-          raise EInvalidNumber (gsValue, value, flength, fscale)
+      else:
+        return int ("%s%s" % (sign, pre))
 
-        sign = vmatch.groups () [0]
-        pre  = vmatch.groups () [1]
-        frac = vmatch.groups () [2]
+    # we know nothing about precision 
+    else:
+      if "." in value:
+        return float (value)
 
-        if len (pre) > (flength-fscale) or len (frac) > fscale:
-          raise EOutOfRange (gsValue, value, flength, fscale)
-
-        if len (frac):
-          return float ("%s%s.%s" % (sign, pre, frac))
-
-        else:
-          return int ("%s%s" % (sign, pre))
-
-      # we know nothing about precision 
       else:
-        if "." in value:
-          return float (value)
-        else:
-          return int (value)
+        return int (value)
       
 
-    # booleans must be 'TRUE' or 'FALSE', otherwise they're "None"
-    elif fieldType == "boolean":
-      bool = fieldValue.upper ().strip ()
+  # booleans must be 'TRUE' or 'FALSE', otherwise they're "None"
+  elif gsValue.dataType == "boolean":
+    bool = fieldValue.upper ().strip ()
 
-      if bool in ["TRUE", "FALSE"]:
-        return bool == "TRUE"
-      else:
-        raise EInvalidBoolean (gsValue, fieldValue)
+    if bool in ["TRUE", "FALSE"]:
+      return bool == "TRUE"
+    else:
+      raise EInvalidBoolean (gsValue, fieldValue)
 
 
-    # Dates must conform with the ISO spec: YYYY-MM-DD
-    elif fieldType == "date":
-      try:
-        return mx.DateTime.ISO.ParseDate (fieldValue.strip ())
+  # Dates must conform with the ISO spec: YYYY-MM-DD
+  elif gsValue.dataType == "date":
+    try:
+      return mx.DateTime.ISO.ParseDate (fieldValue.strip ())
 
-      except ValueError:
-        raise EInvalidDate (gsValue, fieldValue)
+    except ValueError:
+      raise EInvalidDate (gsValue, fieldValue)
 
-      except:
-        raise
+    except:
+      raise
 
     
-    # Times must conform with the ISO spec: HH:[MM[:SS[.ss]]]
-    elif fieldType == "time":
-      try:
-        return mx.DateTime.ISO.ParseTime (fieldValue.strip ())
+  # Times must conform with the ISO spec: HH:[MM[:SS[.ss]]]
+  elif gsValue.dataType == "time":
+    try:
+      return mx.DateTime.ISO.ParseTime (fieldValue.strip ())
 
-      except ValueError:
-        raise EInvalidTime (gsValue, fieldValue)
+    except ValueError:
+      raise EInvalidTime (gsValue, fieldValue)
 
-      except:
-        raise
+    except:
+      raise
 
 
-    # DateTime values must conform with the ISO spec: YYYY-MM-DD HH:MM:SS.ss
-    elif fieldType == "datetime":
-      try:
-        return mx.DateTime.ISO.ParseDateTime (fieldValue.strip ())
+  # DateTime values must conform with the ISO spec: YYYY-MM-DD HH:MM:SS.ss
+  elif gsValue.dataType == "datetime":
+    try:
+      return mx.DateTime.ISO.ParseDateTime (fieldValue.strip ())
 
-      except ValueError:
-        raise EInvalidDateTime (gsValue, fieldValue)
+    except ValueError:
+      raise EInvalidDateTime (gsValue, fieldValue)
 
-      except:
-        raise
+    except:
+      raise
 
 
-    # unhandled types
-    else:
-      raise EInvalidType (gsValue, gsValue.type)
+  # unhandled types
+  else:
+    raise EInvalidType (gsValue, gsValue.dataType)
 
 
 

Modified: trunk/gnue-common/src/schema/GSParser.py
===================================================================
--- trunk/gnue-common/src/schema/GSParser.py    2004-02-29 00:34:46 UTC (rev 
5195)
+++ trunk/gnue-common/src/schema/GSParser.py    2004-02-29 17:24:11 UTC (rev 
5196)
@@ -235,7 +235,23 @@
                'Typecast': GTypecast.name } },
          'ParentTags':  ('data',) },
 
+      'definition': {
+        'BaseClass': Objects.GSDefinition,
+        'SingleInstance': True,
+        'ParentTags': ('tabledata',) },
 
+      'column': {
+        'BaseClass': Objects.GSColumn,
+        'Attributes': {
+          'field': {
+            'Required': True,
+            'Typecast': GTypecast.name },
+          'type': {
+            'Required': True,
+            'Typecast': GTypecast.name }
+          },
+        'ParentTags': ('definition',)},
+
       'rows':   {
          'BaseClass': Objects.GSRows,
          'SingleInstance': 1,

Modified: trunk/gnue-common/src/schema/Objects.py
===================================================================
--- trunk/gnue-common/src/schema/Objects.py     2004-02-29 00:34:46 UTC (rev 
5195)
+++ trunk/gnue-common/src/schema/Objects.py     2004-02-29 17:24:11 UTC (rev 
5196)
@@ -30,8 +30,9 @@
 
 from gnue.common.definitions.GObjects import GObj
 from gnue.common.definitions.GRootObj import GRootObj
-from gnue.common.schema.GSData import valueToNative
+from gnue.common.schema.GSData import verifyDataType, valueToNative
 import GSParser
+import types
 
 class EFoundErrors (Exception):
   def __init__ (self):
@@ -130,17 +131,35 @@
   def __init__(self, parent):
     GSObject.__init__(self, parent, type='GSRow')
 
+# =============================================================================
+# Field-Values
+# =============================================================================
 
 class GSValue(GSObject):
-
+  """
+  This class implements a single data value of a row-collection. On
+  Phase-I-init the values' datatype is determined - either by a matching
+  column-definition, or by a direct type-argument - and a native python object
+  is created for it.
+  """
   def __init__(self, parent):
     GSObject.__init__(self, parent, type='GSValue')
     self.dataType = None
+    self.lenght   = None
+    self.scale    = None
+    self.value    = None
+
     self._inits.append (self._validate)
 
+
   def _validate (self):
+    if hasattr (self, "field"):
+      column = self._findColumn (self.field)
+    else:
+      column = self._findColumn (self._getIndex ())
+
     try:
-      self.value = valueToNative (self)
+      self.value = valueToNative (self, column)
 
     except Exception, message:
       self.value = None
@@ -154,7 +173,104 @@
         parent = parent._parent
 
 
+  # ---------------------------------------------------------------------------
+  # Find a column definition either by it's index or by it's fieldname
+  # ---------------------------------------------------------------------------
 
+  def _findColumn (self, fieldSpec):
+    """
+    This function searches for a given field in a GSTableData's column
+    definition. If @fieldSpec is an integer this number will be used as index
+    to the column-definition collection. Ohterwise @fieldSpec is treated as the
+    field name of the column to be returned.
+    """
+    tableData = self.findParentOfType ('GSTableData')
+    if tableData is not None:
+      colDefs = tableData.findChildOfType ('GSDefinition')
+      if colDefs is not None:
+        return colDefs.getColumn (fieldSpec)
+
+    return None
+
+
+  # ---------------------------------------------------------------------------
+  # get the index of an instance in it's parent's child-collection
+  # ---------------------------------------------------------------------------
+
+  def _getIndex (self):
+    """
+    This function get's the objects index in it's parents child-collection
+    """
+    if self._parent is not None:
+      for index in range (0, len (self._parent._children)):
+        if self._parent._children [index] == self:
+          return index
+
+    raise Exception (_("GSD-Error: can't find myself in the XML tree?!"))
+
+
+
 class GSDescription(GSObject):
   def __init__(self, parent):
     GSObject.__init__(self, parent, type='GSDescription')
+
+
+
+# =============================================================================
+# Column definitions
+# =============================================================================
+
+class GSDefinition (GSObject):
+  """
+  GSDefinition holds a collection of column definition instances. In
+  Phase-I-init a dictionary with all columns is created as well as a sequence
+  of columns (for index-based access).
+  """
+  def __init__ (self, parent):
+    GSObject.__init__ (self, parent, type = "GSDefinition")
+    self.columns = {}
+    self.collist = []
+    self._inits.append (self.__buildColumnDict)
+
+  def __buildColumnDict (self):
+    self.collist = self.findChildrenOfType ('GSColumn')
+    self.columns = {}
+
+    for col in self.collist:
+      self.columns [col.field] = col
+
+
+  def getColumn (self, fieldSpec):
+    """
+    If @fieldSpec is an integer type '@fieldSpec' is treated as an index to the
+    columns-sequence, otherwise @fieldSpec is used as key into the
+    columns-dictionary.
+    """
+    if isinstance (fieldSpec, types.IntType) and fieldSpec < len 
(self.collist):
+      return self.collist [fieldSpec]
+
+    elif self.columns.has_key (fieldSpec):
+      return self.columns [fieldSpec]
+
+    return None
+
+
+# =============================================================================
+# Column definitions
+# =============================================================================
+
+class GSColumn (GSObject):
+  """
+  This class implements a column definition. Phase-I-init verifies the datatype
+  of the column definition and set's the properties 'typename', 'length' and
+  'scale'.
+  """
+  def __init__ (self, parent):
+    GSObject.__init__ (self, parent, type = "GSColumn")
+    self.typename = None
+    self.length   = None
+    self.scale    = None
+    self._inits.append (self._validate)
+
+  def _validate (self):
+    (self.typename, self.length, self.scale) = verifyDataType (self)





reply via email to

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