commit-gnue
[Top][All Lists]
Advanced

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

r5615 - trunk/gnue-appserver/src/classrep


From: johannes
Subject: r5615 - trunk/gnue-appserver/src/classrep
Date: Fri, 2 Apr 2004 05:11:22 -0600 (CST)

Author: johannes
Date: 2004-04-02 05:11:21 -0600 (Fri, 02 Apr 2004)
New Revision: 5615

Modified:
   trunk/gnue-appserver/src/classrep/SchemaSupport.py
Log:
Added create/extend support; improved code


Modified: trunk/gnue-appserver/src/classrep/SchemaSupport.py
===================================================================
--- trunk/gnue-appserver/src/classrep/SchemaSupport.py  2004-04-02 10:53:54 UTC 
(rev 5614)
+++ trunk/gnue-appserver/src/classrep/SchemaSupport.py  2004-04-02 11:11:21 UTC 
(rev 5615)
@@ -1,7 +1,4 @@
-# GNU Enterprise Application Server - GNUe Schema Support
 #
-# Copyright 2003-2004 Free Software Foundation
-#
 # This file is part of GNU Enterprise.
 #
 # GNU Enterprise is free software; you can redistribute it
@@ -19,287 +16,371 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
+# Copyright 2001-2004 Free Software Foundation
+#
 # $Id$
 
-from types import *
-
 import sys
+import types
 import mx.DateTime.ISO
-import re
 
-from gnue.common.schema.Objects import *
-from gnue.common.definitions.GParserHelpers import GContent
+from gnue.common.schema import Objects
+from gnue.common.definitions import GParserHelpers
 from gnue.appserver.classrep import Namespace
 
 # =============================================================================
-# Exceptions: Base exception class
+# Exceptions
 # =============================================================================
 
+# -----------------------------------------------------------------------------
+# Base exception
+# -----------------------------------------------------------------------------
+
 class SchemaSupportError (gException):
-  """
-  Base class for all exceptions of SchemaSupport
-  """
-  def __init__ (self, text):
-    gException.__init__ (self, text)
+  pass
 
+# -----------------------------------------------------------------------------
+# Invalid export type
+# -----------------------------------------------------------------------------
 
-class InvalidTypeError (SchemaSupportError):
-  def __init__ (self, typename):
-    msg = _("Invalid export type: '%s'") % typename
+class ExportTypeError (SchemaSupportError):
+  def __init__ (self, exportType):
+    msg = _("Invalid export type: '%s'") % exportType
     SchemaSupportError.__init__ (self, msg)
 
+# -----------------------------------------------------------------------------
+# Invalid value for given type of 
+# -----------------------------------------------------------------------------
 
-class InvalidValueError (SchemaSupportError):
-  """
-  This exception is raised if a value doesn't match it's datatype.
-  """
-  def __init__ (self, text):
-    SchemaSupportError.__init__ (self, text)
+class ValueError (SchemaSupportError):
+  pass
 
 
 # =============================================================================
-# SchemaSupport
+# 
 # =============================================================================
+
 class SchemaSupport:
 
-  SCHEMA_STORE = ["schema", "data", "both"]
-
   # ---------------------------------------------------------------------------
   # Constructor
   # ---------------------------------------------------------------------------
-  def __init__(self, modules, classes):
+
+  def __init__ (self, modules, classes):
     self.__modules = modules
     self.__classes = classes
 
+    self.__exportModules = {}
+    self.__exportClasses = {}
 
+    self.__schema   = None
+    self.__tables   = None
+    self.__data     = None
+    self.__dataRows = {}
+
+
   # ---------------------------------------------------------------------------
-  # Write a Schema to a file. If filename is omitted stdout is used.
+  # Write the requested items to a GNUe Schema Definition
   # ---------------------------------------------------------------------------
-  def writeSchemaToFile (self, filename = None, items = None, wtype = None):
-    if wtype is None:
-      wtype = "both"
 
-    elif wtype.lower () not in self.SCHEMA_STORE:
-      raise InvalidTypeError (wtype.lower ())
+  def writeSchemaToFile (self, filename = None, items = None, wType = None):
+    """
+    This function creates an XML object tree for all the requested @items,
+    containing a tabledefinition and a datadefinition as given by @wType, and
+    dumps this XML object tree to filename. If filename is omitted sys.stdout
+    will be used.
+    """
+    checktype (filename, [types.NoneType, types.StringType, types.UnicodeType])
+    checktype (items,    [types.NoneType, types.ListType])
+    checktype (wType,    [types.NoneType, types.StringType, types.UnicodeType])
 
-    # If no specific items are requested, we will use classes
+    # do we have a usable export type given
+    if wType is None:
+      wType = 'both'
+
+    elif wType.lower () not in ['schema', 'data', 'both']:
+      raise ExportTypeError, wType.lower ()
+
+    # build a todo-list: if no specific item is reqested, we will use all
+    # classes. Requested items are separated into modules and classes
+    self.__exportModules = {}
+    self.__exportClasses = {}
+
     if items is None or len (items) == 0:
-      classdefs = self.__classes.values ()
+      items = [aClass.fullName for aClass in self.__classes.values ()]
 
-    # otherwise check all items and create the classlist
-    else:
-      classdefs = []
+    for item in items:
+      # item is a module
+      if Namespace.getNamespaceId (item) == Namespace.NSID_MODULE:
+        aModule = self.__modules [item]
+        self.__exportModules [aModule.fullName] = aModule
 
-      for item in items:
-        # if item is a module add all it's classes to the list
-        if Namespace.getNamespaceId (item) == Namespace.NSID_MODULE:
-          classdefs.extend (self.__modules [item].classes.values ())
+      # or a class
+      elif Namespace.getNamespaceId (item) == Namespace.NSID_CLASS:
+        aClass = self.__classes [item]
+        self.__exportClasses [aClass.fullName] = aClass
 
-        # if item is a class add it to the list
-        elif Namespace.getNamespaceId (item) == Namespace.NSID_CLASS:
-          classdefs.append (self.__classes [item])
+      else:
+        # or invalid
+        raise Namespace.InvalidNameError, item
 
-        # otherwise item is of no use to us
-        else:
-          raise Namespace.InvalidNameError (item)
+    # create the top-level objects of the XML tree
+    self.__schema = Objects.GSSchema ()
+    self.__schema.title   = 'Appserver Schema Dump'
+    self.__schema.author  = 'Appserver SchemaSupport'
+    self.__schema.version = '1.0'
 
-    schema = GSSchema()
-    schema.title   = "Appserver Schema Dump"
-    schema.author  = "Appserver SchemaSupport"
-    schema.version = "1.0"
+    self.__tables = None
+    self.__data   = None
 
-    gsTables = GSTables (schema)
+    if wType.lower () in ['both', 'schema']:
+      self.__tables = Objects.GSTables (self.__schema)
+    if wType.lower () in ['both', 'data']:
+      self.__data = Objects.GSData (self.__schema)
 
-    # Schema-Definition
-    if wtype.lower () in ["both", "schema"]:
-      for classdef in classdefs:
-        self.__createTableDef (gsTables, classdef)
+    # if there is a list of requested modules, add them to the gnue_module_dump
+    # before class dumps
+    if self.__data is not None and len (self.__exportModules.keys ()):
+      self.__addModuleDump ()
 
-    # Data
-    if wtype.lower () in ["both", "data"]:
-      gsData = GSData (schema)
-      self.__createDataList (gsData, classdefs)
+    # iterate over all available classes in the repository
+    for aClass in self.__classes.values ():
 
-    if filename is None:
-      dest = sys.stdout
+      # class is requested explicitly, so do a 'full create export'
+      if self.__exportClasses.has_key (aClass.fullName):
+        self.__export (aClass, True)
+
+      # if the module of a class is requested, export all stuff of this module
+      # plus gnue_*-things (using create action)
+      elif self.__exportModules.has_key (aClass.gnue_module.gnue_name):
+        self.__export (aClass, True, self.__exportModules.keys () + ['gnue'])
+
+      else:
+        # if aClass has a property or procedure of a requested module, export
+        # all stuff of the requested modules (using an extend action)
+        xModules = [p.module.fullName for p in aClass.properties.values () + \
+                                               aClass.procedures.values ()]
+        for module in xModules:
+          if module == 'gnue': 
+            continue
+          if self.__exportModules.has_key (module):
+            self.__export (aClass, False, self.__exportModules.keys ())
+            break
+
+
+    # The XML object tree is complete now, so we're going to dump it
+    if filename is not None:
+      destination = open (filename, 'w')
     else:
-      dest = open (filename, 'w')
+      destination = sys.stdout
 
-    dest.write ('<?xml version="1.0" encoding="UTF-8"?>\n')
-    dest.write ('<!-- Schema definition created by GNUe Appserver\'s ' + \
-                'Schema Support. -->\n')
-    dest.write ("<!-- run this file through gnue-schema to create SQL " + \
-                "scripts -->\n")
-    dest.write (schema.dumpXML ().encode ('utf-8'))
-    dest.close ()
+    header = """<?xml version="1.0" encoding="UTF-8"?>
+<!-- Schema definition created by GNUe Appserver's Schema Support. 
+     Run this file through gnue-schema to create SQL scripts       -->
+"""
+    destination.write (header)
+    destination.write (self.__schema.dumpXML ().encode ('utf-8'))
+    destination.close ()
 
 
+
   # ---------------------------------------------------------------------------
-  # Create the tabledefinition for classname
+  # Export a given class (schema and data)
   # ---------------------------------------------------------------------------
-  def __createTableDef (self, gsTables, classdef):
 
-    table      = GSTable (gsTables)
-    table.name = classdef.table
+  def __export (self, aClass, create, modules = None):
+    """
+    This function exports schema- and data-definition of a given class. If
+    @create is True, the schema-definition is given as 'create'-action,
+    otherwise an 'extend'-action will be used. @modules is a list of
+    modulenames, whose properties and procedures should be exported. If no list
+    is given, all properties and procedures will be exported.
+    """
+    if self.__tables is not None:
+      self.__exportSchema (aClass, create, modules)
 
-    # add fields listing (required)
-    fields = GSFields (table)
-    GSConstraints (table)
-    GSIndexes (table)
+    if self.__data is not None:
+      self.__exportData (aClass, create, modules)
 
-    for cProp in classdef.properties.values ():
-      field = GSField (fields)
+
+
+  # ---------------------------------------------------------------------------
+  # Add a class to the table-definition tree
+  # ---------------------------------------------------------------------------
+
+  def __exportSchema (self, aClass, create, modules = None):
+    """
+    This function adds a classes schema to the XML object tree.
+    """
+
+    schema = Objects.GSTable (self.__tables)
+    schema.name = aClass.table
+    if not create:
+      schema.action = "extend"
+
+    fields      = Objects.GSFields (schema)
+    indexes     = Objects.GSIndexes (schema)
+    constraints = Objects.GSConstraints (schema)
+
+    # populate the fields-collection
+    for cProp in self.__filterByModules (aClass.properties.values (), modules):
+      field = Objects.GSField (fields)
       field.name        = cProp.column
       field.description = cProp.gnue_comment
       field.type        = cProp.dbType
-      if cProp.dbLength: field.length    = cProp.dbLength
-      if cProp.dbScale : field.precision = cProp.dbScale
+      if cProp.dbLength:
+        field.length    = cProp.dbLength
+      if cProp.dbScale:
+        field.scale     = cProp.dbScale
       if not cProp.gnue_nullable is None and not cProp.gnue_nullable:
-        field.nullable = False
+        field.nullable  = False
 
-    # If there is a property 'gnue_id' of type 'id' in a class use it for the
-    # primary key
-    if classdef.properties.has_key ("gnue_id"):
-      if classdef.properties ["gnue_id"].gnue_type == "id":
-        pk = GSPrimaryKey (table)
-        pk.name = "gnue_id_pk_%s" % classdef.table
+      # if a type has an underscore we assume it's a reference-type, which
+      # means to create a foreign key reference to the gnue_id of that class
+      if "_" in cProp.gnue_type:
+        constraint = Objects.GSConstraint (constraints)
+        constraint.name = "%s_%s_fk" % (aClass.table, cProp.column)
+        constraint.type = "foreignkey"
 
-        pkf = GSPKField (pk)
-        pkf.name = 'gnue_id'
+        constField = Objects.GSConstraintField (constraint)
+        constField.name = cProp.fullName
 
+        constRef = Objects.GSConstraintRef (constraint)
+        constRef.name  = "gnue_id"
+        constRef.table = cProp.gnue_type
 
+    # in create-mode look if a primary key could be constructed
+    if create and aClass.properties.has_key ('gnue_id'):
+      if aClass.properties ['gnue_id'].gnue_type == 'id':
+        primarykey = Objects.GSPrimaryKey (schema)
+        primarykey.name = "gnue_id_pk_%s" % aClass.table
+
+        pkField = Objects.GSPKField (primarykey)
+        pkField.name = 'gnue_id'
+
+
+
   # ---------------------------------------------------------------------------
-  # Dump all tabledata from a given tablelist
+  # Add a class to the data definition 
   # ---------------------------------------------------------------------------
-  def __createDataList (self, gsData, classdefs):
-    # first we need a list of all modules used in classdefs
-    modules = {}
-    for classdef in classdefs:
-      modules [classdef.module.fullName] = classdef.module
 
-    # dump one row from gnue_module for all items in modules
-    moddata = GSTableData (gsData)
-    moddata.name      = 'gnue_module_dump'
-    moddata.tablename = 'gnue_module'
-    self.__addColumnDefinition (moddata, 'gnue_module')
-    modrows = GSRows (moddata)
+  def __exportData (self, aClass, create, modules = None):
+    """
+    This function adds @aClass to several gnue-table rows.
+    """
+    if create:
+      self.__dumpObject (aClass, 'gnue_class')
 
-    for moduledef in modules.values ():
-      mProp = self.__classes ["gnue_module"].properties
-      row   = GSRow (modrows)
+    for prop in self.__filterByModules (aClass.properties.values (), modules):
+      self.__dumpObject (prop, 'gnue_property')
 
-      self.__buildValue (row, mProp [u"gnue_id"]     , moduledef.gnue_id)
-      self.__buildValue (row, mProp [u"gnue_name"]   , moduledef.gnue_name)
-      self.__buildValue (row, mProp [u"gnue_comment"], moduledef.gnue_comment)
+    for proc in self.__filterByModules (aClass.procedures.values (), modules):
+      self.__dumpObject (proc, 'gnue_procedure')
 
-    # 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)
+      for param in proc.parameters.values ():
+        self.__dumpObject (param, 'gnue_parameter')
 
-    # 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)
+  # ---------------------------------------------------------------------------
+  # Dump an object to the given table
+  # ---------------------------------------------------------------------------
 
-    # and all the procedures parameters
-    paramdata = GSTableData (gsData)
-    paramdata.name      = 'gnue_parameter_dump'
-    paramdata.tablename = 'gnue_parameter'
-    tableDef = self.__addColumnDefinition (paramdata, 'gnue_parameter')
-    paramrows = GSRows (paramdata)
+  def __dumpObject (self, aClass, table):
+    """
+    This function creates a new row of @table, and adds all values from @aClass
+    according to the classdefinition of @table to it.
+    """
+    row = Objects.GSRow (self.__getRows (table))
+    
+    for cProp in self.__classes [table].properties.values ():
+      value = getattr (aClass, cProp.fullName)
+      
+      # resolve reference-properties
+      if "_" in cProp.fullType:
+        value = value.gnue_id
 
-    for classdef in classdefs:
-      cProp = self.__classes ["gnue_class"].properties
+      self.__buildValue (row, cProp, value)
 
-      # 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_comment"], classdef.gnue_comment)
+  # ---------------------------------------------------------------------------
+  # Get the rows object of an tabledata-object
+  # ---------------------------------------------------------------------------
 
-      for propdef in classdef.properties.values ():
+  def __getRows (self, classname):
+    """
+    This function returns the rows-collection of a given table. If it does not
+    exist already it will be created (with a column definition included).
+    """
 
-        pProp = self.__classes ["gnue_property"].properties
-        row = GSRow (proprows)
+    if not self.__dataRows.has_key (classname):
+      table = Objects.GSTableData (self.__data)
+      table.name      = "%s_dump" % classname
+      table.tablename = classname
 
-        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)
-        self.__buildValue (row, pProp ["gnue_nullable"], propdef.gnue_nullable)
+      columns = Objects.GSDefinition (table)
 
-      for procdef in classdef.procedures.values ():
+      for prop in self.__classes [classname].properties.values ():
+        column = Objects.GSColumn (columns)
+        column.field = prop.column
+        column.type  = prop.dbFullType
 
-        pProp = self.__classes ["gnue_procedure"].properties
-        row = GSRow (procrows)
+      self.__dataRows [classname] = Objects.GSRows (table)
 
-        self.__buildValue (row, pProp ["gnue_id"],       procdef.gnue_id)
-        self.__buildValue (row, pProp ["gnue_module"],   procdef.gnue_module)
-        self.__buildValue (row, pProp ["gnue_class"],    procdef.gnue_class)
-        self.__buildValue (row, pProp ["gnue_name"],     procdef.gnue_name)
-        self.__buildValue (row, pProp ["gnue_language"], procdef.gnue_language)
-        self.__buildValue (row, pProp ["gnue_code"],     procdef.gnue_code)
-        self.__buildValue (row, pProp ["gnue_comment"],  procdef.gnue_comment)
+    return self.__dataRows [classname]
 
-        for paramDef in procdef.parameters.values ():
-          pProp = self.__classes ["gnue_parameter"].properties
-          row = GSRow (paramrows)
 
-          self.__buildValue (row, pProp ["gnue_id"],      paramDef.gnue_id)
-          self.__buildValue (row, pProp ["gnue_procedure"],
-                                                    paramDef.gnue_procedure)
-          self.__buildValue (row, pProp ["gnue_name"],    paramDef.gnue_name)
-          self.__buildValue (row, pProp ["gnue_type"],    paramDef.gnue_type)
-          self.__buildValue (row, pProp ["gnue_length"],  paramDef.gnue_length)
-          self.__buildValue (row, pProp ["gnue_scale"],   paramDef.gnue_scale)
-          self.__buildValue (row, pProp ["gnue_comment"], 
paramDef.gnue_comment)
-
-
   # ---------------------------------------------------------------------------
-  # Create a new field in a row and populate it with a value
+  # Create a GContents XML object for a data value in a row
   # ---------------------------------------------------------------------------
+
   def __buildValue (self, row, prop, data):
+    """
+    If @data is not None this function adds a GContents object with the
+    normalized value of @data to the @row, where @prop specifies the datatype
+    for normalization.
+    """
     if data is not None:
-      value = GSValue (row)
+      value = Objects.GSValue (row)
       value.field = prop.column
-      GContent (value, self.__nativeToString (data, prop.fullType))
+      GParserHelpers.GContent (value, \
+                               self.__nativeToString (data, prop.dbFullType))
 
 
   # ---------------------------------------------------------------------------
-  # Add a column definition section to the given tabledata for classname
+  # Get a subsequence of items matching a modulelist
   # ---------------------------------------------------------------------------
 
-  def __addColumnDefinition (self, tableData, classname):
-    tableDef = GSDefinition (tableData)
+  def __filterByModules (self, items, modules):
+    """
+    This function returns a sub-sequence of all @items which match the given
+    module list (@modules). If this list is None, all @items are returned.
+    """
+    result = []
+    for element in items:
+      if modules is not None and not element.module.fullName in modules:
+        continue
 
-    classdef = self.__classes [classname]
-    for prop in classdef.properties.values ():
-      column = GSColumn (tableDef)
-      column.field = prop.column
-      column.type = prop.dbFullType
+      result.append (element)
 
-    return tableDef
+    return result
 
 
+
   # ---------------------------------------------------------------------------
+  # add all requested modules to the module dump
+  # ---------------------------------------------------------------------------
+
+  def __addModuleDump (self):
+    """
+    This function creates a dump of the gnue_module table, by adding all
+    requested modules.
+    """
+    for module in self.__exportModules.values ():
+      self.__dumpObject (module, 'gnue_module')
+
+
+
+  # ---------------------------------------------------------------------------
   # Convert a native python object to a string according to datatype
   # ---------------------------------------------------------------------------
 
@@ -310,12 +391,12 @@
     'datatype'.
     """
     if datatype [:6] == "string" or datatype == "id":
-      checktype (native, [NoneType, UnicodeType])
+      checktype (native, [types.NoneType, types.UnicodeType])
 
       if native is None:
         return u''
 
-      if isinstance (native, UnicodeType):
+      if isinstance (native, types.UnicodeType):
         return native
 
     elif datatype [:6] == "number":
@@ -337,8 +418,7 @@
         return native.date
 
       else:
-        raise InvalidValueError ( \
-              _("%s is not a valid date object") % repr (native))
+        raise ValueError (_("%s is not a valid date object") % repr (native))
 
 
     elif datatype == "time":
@@ -349,8 +429,7 @@
         return str (native)
 
       else:
-        raise InvalidValueError ( \
-              _("%s is not a valid time object") % repr (native))
+        raise ValueError (_("%s is not a valid time object") % repr (native))
 
 
     elif datatype == "datetime":
@@ -358,24 +437,9 @@
         return str (native)
 
       else:
-        raise InvalidValueError (_("%s is not a valid datetime object") % \
+        raise ValueError (_("%s is not a valid datetime object") % \
                                     repr (native))
 
     else:
       # must be reference property
       return native.gnue_id
-
-
-# =============================================================================
-# test program
-# =============================================================================
-
-if __name__ == '__main__':
-  from gnue.appserver.test import testApp
-
-  app = testApp()
-  sm = app.getSessionManager ()
-
-  gsdSupp = SchemaSupport (sm.modules, sm.classes)
-
-  gsdSupp.writeSchemaToFile ('AS_Schema.gsd')





reply via email to

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