commit-gnue
[Top][All Lists]
Advanced

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

r6467 - trunk/gnue-appserver/src


From: johannes
Subject: r6467 - trunk/gnue-appserver/src
Date: Mon, 11 Oct 2004 04:12:50 -0500 (CDT)

Author: johannes
Date: 2004-10-11 04:12:49 -0500 (Mon, 11 Oct 2004)
New Revision: 6467

Modified:
   trunk/gnue-appserver/src/geasGsdGen.py
Log:
*) added supports of 'include-details' option
*) added support of filters; one can now select data to be exported using 
filters on the commandline like: foobar.barbaz=someval


Modified: trunk/gnue-appserver/src/geasGsdGen.py
===================================================================
--- trunk/gnue-appserver/src/geasGsdGen.py      2004-10-10 18:33:35 UTC (rev 
6466)
+++ trunk/gnue-appserver/src/geasGsdGen.py      2004-10-11 09:12:49 UTC (rev 
6467)
@@ -23,12 +23,14 @@
 
 import sys
 import types
+import copy
+import string
 import mx.DateTime
 
 from gnue.common.apps import i18n, errors
 from gnue.common.schema import Objects
 from gnue.common.apps.GClientApp import *
-from gnue.common.datasources import GDataSource
+from gnue.common.datasources import GDataSource, GConditions
 from gnue.common.definitions import GParserHelpers
 
 from gnue.appserver import VERSION
@@ -41,10 +43,15 @@
 
 class CircularReferenceError (errors.ApplicationError):
   def __init__ (self):
-    msg = _("Classes have circular or unresolveable references")
+    msg = u_("Classes have circular or unresolveable references")
     errors.ApplicationError.__init__ (self, msg)
 
+class CircularFishHookError (errors.UserError):
+  def __init__ (self, classname):
+    msg = u_("The class '%s' contains circular data-references") % classname
+    errors.UserError.__init__ (self, msg)
 
+
 # =============================================================================
 # Generate GNUe Schema Definition files
 # =============================================================================
@@ -58,8 +65,6 @@
   SUMMARY = _("A tool to dump data from a database into a GNUe Schema "
               "Definition (gsd) file.")
 
-
-
   # ---------------------------------------------------------------------------
   # Constructor
   # ---------------------------------------------------------------------------
@@ -76,6 +81,10 @@
     self.addCommandOption ('system', 's', default = False,
         help = _("If flag is set include system classes ('gnue_*')"))
 
+    self.addCommandOption ('include-details', 'i', default = False,
+        help = _("If set all detail-classes of the requestd classes will be "
+          "exported too"))
+
     ConfigOptions = {}
 
     GClientApp.__init__ (self, connections, 'appserver', ConfigOptions)
@@ -88,191 +97,213 @@
     if self.OPTIONS ["database"] is not None:
       cparser.set ('appserver', 'database', self.OPTIONS ["database"])
 
+    self.__filterParams = self.__getFilterParams ()
+    self.__useFilter    = False
 
+
   # ---------------------------------------------------------------------------
   # Main program
   # ---------------------------------------------------------------------------
 
   def run (self):
+    """
+    This is the main function of the gsd generator. If parses the options
+    given, creates the GSD object tree and dumps it to the output file.
+    """
+
     if self.OPTIONS ['output'] is None:
       raise StartupError, u_("No output file specified.")
 
     self.__filename = self.OPTIONS ['output']
     args = [unicode (a, i18n.encoding) for a in self.ARGUMENTS]
 
-    print _("Loading class repository ...")
+    print o(u_("Loading class repository ..."))
 
     self.sm = geasSessionManager (self.connections)
+    self.filters = self.__verifyFilters ()
+    self.__useFilter = len (self.filters.keys ()) > 0
 
-    print _("Generating schema definition ...")
+    print o(u_("Building list of classes and calculating dependencies ..."))
 
-    try:
-      self._createClassList (args)
+    self.exports    = self.__createClassList (args)
+    self.conditions = self.__createConditionDicts ()
 
-      schema = Objects.GSSchema ()
-      schema.title   = 'Appserver Data Dump'
-      schema.author  = self.COMMAND
-      schema.version = '1.0'
-      self._data = Objects.GSData (schema)
+    print o(u_("Generating schema definition ..."))
 
-      for classname in self.exports:
-        self._exportClass (classname)
+    schema = Objects.GSSchema ()
+    schema.title   = 'Appserver Data Dump'
+    schema.author  = self.COMMAND
+    schema.version = '1.0'
+    self._data = Objects.GSData (schema)
 
-      dest = open (self.__filename, "w")
-      dest.write ("""<?xml version="1.0" encoding="UTF-8"?>\n""")
-      dest.write (schema.dumpXML ().encode ('utf-8'))
-      dest.close ()
+    for classname in self.exports:
+      self.__exportClass (classname)
 
+    dest = open (self.__filename, "w")
+    dest.write ("""<?xml version="1.0" encoding="UTF-8"?>\n""")
+    dest.write (schema.dumpXML ().encode ('utf-8'))
+    dest.close ()
 
-    except Exception:
-      msg = "%s\n" % str (sys.exc_info () [1])
-      sys.stderr.write (msg)
-      sys.exit (1)
+    print o(u_("Generation run complete."))
 
-    print _("Generation run complete.")
 
-
   # ---------------------------------------------------------------------------
-  # Create a list of classes to be exported
+  # Export data of a given class
   # ---------------------------------------------------------------------------
 
-  def _createClassList (self, args):
+  def __exportClass (self, className):
     """
-    This function creates a sequence of classnames to be dumped. This sequence
-    is in a proper order so no constraint-violations should occur.
+    Create a TableData object tree with all data of the given class.
+
+    @param className: fully qualified name of the class to be exported
     """
-    if not len (args):
-      for c in self.sm.classes.values ():
-        if not self.OPTIONS ['system'] and c.module.fullName == 'gnue':
-          continue
 
-        args.append (c.fullName)
+    cDef  = self.sm.classes [className]
+    print o(u_("Exporting data of class '%s' ...") % className)
 
-    self.classes = {}
-    for cName in args:
-      self._addClass (cName)
+    # Prepare the tabledata- and it's definition tags
+    table = Objects.GSTableData (self._data)
+    table.name      = "%s_dump" % cDef.table
+    table.tablename = cDef.table
 
-    self.exports = []
-    res = self._shrinkList ()
+    columns = Objects.GSDefinition (table)
 
-    while len (res):
-      self.exports.extend (res)
-      res = self._shrinkList ()
+    fieldlist = []
+    for prop in cDef.properties.values ():
+      if prop.isCalculated: continue
 
+      column = Objects.GSColumn (columns)
+      column.field = prop.column
+      column.type  = prop.dbFullType
 
+      if prop.fullName == 'gnue_id':
+        column.key = True
 
+      fieldlist.append (prop.column)
+
+    rows = Objects.GSRows (table)
+
+    if self.__fishes.has_key (className):
+      self.__fishDataDump (cDef, fieldlist, rows)
+    else:
+      self.__normalDataDump (cDef, fieldlist, rows)
+
+
   # ---------------------------------------------------------------------------
-  # add a class to the classlist and iterate over all references
+  # Dump all records of a class without any sorting stuff
   # ---------------------------------------------------------------------------
 
-  def _addClass (self, className):
+  def __normalDataDump (self, classDef, fieldlist, rows):
     """
-    This function adds a class to the list of classes respecting all
-    dependencies given by class-references.
+    This function creates a resultset for the given class and iterates over all
+    records. All fields with a value other than <None> will be added to the
+    rows collection.
+
+    @param classDef: class definition of the class to be dumped
+    @param fieldlist: list of fieldnames to be exported
+    @param rows: GSRows collection to which new records will be added
     """
-    cDef = self.sm.classes [className]
-    if not self.classes.has_key (className):
-      self.classes [className] = []
 
-    for p in cDef.properties.values ():
-      if p.isReference:
-        refClass = p.referencedClass.fullName
-        if not refClass in self.classes [className]:
-          self.classes [className].append (refClass)
-        self._addClass (refClass)
+    (dts, fields) = self.__openSource (classDef, fieldlist)
 
+    resultSet = dts.createResultSet ()
+    record    = resultSet.firstRecord ()
 
+    while record is not None:
+      self.__addRow (record, classDef, fields, rows)
+      record = resultSet.nextRecord ()
+
+
   # ---------------------------------------------------------------------------
-  # Return all items from the classlist, which have no dependencies
+  # Create a row object and add it to the rows collection
   # ---------------------------------------------------------------------------
 
-  def _shrinkList (self):
+  def __addRow (self, record, classDef, fields, rows):
     """
-    This function returns a sequence of all classes without any dependencies.
-    If no such classes were found but there are still classes in the dictionary
-    a CircularReferenceError will be raised.
+    This function adds a new row to the given row collection using the values
+    from the given record.
+
+    @param record: record which should be exported
+    @param classDef: class definition of the record
+    @param fields: sequence of fieldnames to be exported
+    @param rows: GSRows instance which is parent of the newly created rows
     """
-    result = []
 
-    for (classname, refs) in self.classes.items ():
-      if not len (refs):
-        result.append (classname)
+    row = Objects.GSRow (rows)
 
-        for ref in self.classes.values ():
-          if classname in ref:
-            ref.remove (classname)
+    for field in fields:
+      pName = "." in field and field.split (".", 1) [-1] or field
+      prop  = classDef.properties [pName]
+      data  = record.getField (field)
 
-        del self.classes [classname]
+      if data is not None:
+        value = Objects.GSValue (row)
+        value.field = prop.column
 
-    if not len (result) and len (self.classes.keys ()):
-      raise CircularReferenceError
+        GParserHelpers.GContent ( \
+          value, self.__nativeToString (data, prop.dbFullType))
 
-    return result
 
-
   # ---------------------------------------------------------------------------
-  # Export data of a given class
+  # Export data from a class with a fishhook
   # ---------------------------------------------------------------------------
 
-  def _exportClass (self, className):
+  def __fishDataDump (self, classDef, fieldlist, rows):
     """
-    Create a TableData object tree with all data of the given class.
+    This function exports all records (according to an existing filter) of a
+    class which has a fishhook. All records are exported in an order which
+    allows reimporting without reference-violation.
+
+    @param classDef: class definition of the class to be dumped
+    @param fieldlist: list of fieldnames to be exported
+    @param rows: GSRows collection to which new records will be added
     """
-    cDef  = self.sm.classes [className]
-    print u_("Exporting data of class '%s' ...") % className
 
-    # Prepare the tabledata- and it's definition tags
-    table = Objects.GSTableData (self._data)
-    table.name      = "%s_dump" % cDef.table
-    table.tablename = cDef.table
+    (dts, fields) = self.__openSource (classDef, fieldlist)
 
-    columns = Objects.GSDefinition (table)
+    dataDict  = {}
+    idField   = 't0.gnue_id' in fields and 't0.gnue_id' or 'gnue_id'
+    className = classDef.fullName
+    resultSet = dts.createResultSet ()
 
-    fieldlist = []
-    for prop in cDef.properties.values ():
-      if prop.isCalculated: continue
+    # first we create a dependency-tree for all records
+    record    = resultSet.firstRecord ()
 
-      column = Objects.GSColumn (columns)
-      column.field = prop.column
-      column.type  = prop.dbFullType
+    while record is not None:
+      gnue_id = record.getField (idField)
 
-      fieldlist.append (prop.column)
+      if not dataDict.has_key (gnue_id):
+        dataDict [gnue_id] = []
 
-    rows = Objects.GSRows (table)
+      for ref in self.__fishes [classDef.fullName]:
+        rField = "t0.%s" % ref in fields and "t0.%s" % ref or ref
+        refId = record.getField (rField)
+        if refId is not None and not refId in dataDict [gnue_id]:
+          dataDict [gnue_id].append (refId)
 
-    # Create a datasource for the given class
-    attrs = {'name'    : "dts_%s" % cDef.table,
-             'database': self.sm._internalSession.database,
-             'table'   : cDef.table}
-    dts = GDataSource.DataSourceWrapper ( \
-        connections = self.connections,
-        attributes  = attrs,
-        fields      = fieldlist,
-        unicodeMode = True)
+      record = resultSet.nextRecord ()
 
-    rs = dts.createResultSet ()
+    # now create an ordered sequence from that dependency tree
+    result = []
+    add = self.__shrinkList (dataDict, CircularFishHookError, className)
 
-    rec = rs.firstRecord ()
+    while len (add):
+      result.extend (add)
+      add = self.__shrinkList (dataDict, CircularFishHookError, className)
 
-    while rec is not None:
-      row = Objects.GSRow (rows)
+    # and export all records according to this order
+    for gnue_id in result:
+      record = resultSet.firstRecord ()
 
-      for prop in cDef.properties.values ():
-        if prop.isCalculated: continue
+      while record is not None:
+        if record.getField (idField) == gnue_id:
+          self.__addRow (record, classDef, fields, rows)
+          break
 
-        data = rec.getField (prop.column)
-        if data is not None:
-          value = Objects.GSValue (row)
-          value.field = prop.column
-          if prop.column == 'gnue_id':
-            value.key = True
-          GParserHelpers.GContent ( \
-            value, self.__nativeToString (data, prop.dbFullType))
+        record = resultSet.nextRecord ()
 
-      rec = rs.nextRecord ()
 
 
-
   # ---------------------------------------------------------------------------
   # Convert a native python object to a string according to datatype
   # ---------------------------------------------------------------------------
@@ -280,9 +311,10 @@
   def __nativeToString (self, native, datatype):
     """
     This function creates a unicode string to be used in a <value>-tag of a GSD
-    file.  The native python object will be treated and theirfore converted as
+    file. The native python object will be treated and theirfore converted as
     'datatype'.
     """
+
     if datatype [:6] == "string" or datatype == "id":
       checktype (native, [types.NoneType, types.UnicodeType])
 
@@ -293,12 +325,8 @@
         return native
 
     elif datatype [:6] == "number":
-      if native is None:
-        return "0"
-      else:
-        return str (native)
+      return native is None and "0" or str (native)
 
-
     elif datatype == "boolean":
       if native is not None and native:
         return u'TRUE'
@@ -330,13 +358,411 @@
         return str (native)
 
       else:
-        raise ValueError, u_("%s is not a valid datetime object") % repr 
(native)
+        raise ValueError, \
+            u_("%s is not a valid datetime object") % repr (native)
 
     else:
       # must be reference property
       return native.gnue_id
 
 
+
+  # ---------------------------------------------------------------------------
+  # fetch and remove all 'filter'-like parameters from the command line
+  # ---------------------------------------------------------------------------
+
+  def __getFilterParams (self):
+    """
+    This function iterates over the command line arguments, picks out all
+    elements with an equal sign and removes them from the arguments sequence
+    Such elements are of the form 'classname[.property]=value' where the
+    property part is optional. From all these elements a dictionary is built
+    where the 'classname'-part acts as key and the value is another dictionary
+    with 'property'-part as key an 'value' as it's value. If no 'property' is
+    given 'gnue_id' will be used.
+
+    @return: dictionary with filter-parameters and their requested values
+    """
+
+    result  = {}
+
+    # First we catch all 'foo=bar' like arguments
+    for item in self.ARGUMENTS [:]:
+      if '=' in item:
+        (name, value) = item.split ('=')
+
+        if not len (name):
+          raise StartupError, u_("Invalid command line argument '='")
+        if not len (value):
+          raise StartupError, \
+              u_("Filter '%s' started, but no value given") % name
+
+        self.ARGUMENTS.remove (item)
+
+        # and put them into a dictionary
+        parts = name.strip ().split ('.', 1)
+        field = len (parts) == 1 and 'gnue_id' or parts [1]
+
+        # if a filter has more than one field
+        if not result.has_key (parts [0]):
+          result [parts [0]] = {}
+
+        result [parts [0]][field] = value
+
+    gDebug (1, "Filter-Params: %s" % result)
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Verify the requested filters
+  # ---------------------------------------------------------------------------
+
+  def __verifyFilters (self):
+    """
+    This function iterates over all available filters and creates a dictionary
+    with all filter-ids and their values. 
+    @return: dictionary with gnue-id of the filter-class as key and the gnue-id
+        of the filter-value as value
+    """
+
+    result = {}
+    fNames = {}
+
+    # first replace all class-names by there gnue-id's
+    for (filterName, data) in self.__filterParams.items ():
+      if not self.sm.classes.has_key (filterName):
+        raise StartupError, u_("Filter class '%s' not found") % filterName
+
+      fc = self.sm.classes [filterName]
+      for field in data.keys ():
+        if not fc.properties.has_key (field):
+          raise StartupError, \
+              u_("Filter '%(class)s' has no property '%(property)s'") \
+              % {'class'   : filterName,
+                 'property': field}
+
+      self.__filterParams [fc.gnue_id] = data
+      fNames [fc.gnue_id] = filterName
+      del self.__filterParams [filterName]
+
+    srvFilters = self.sm.getFilters (i18n.getuserlocale ())
+
+    for (filterId, fields, master, values) in srvFilters:
+      if self.__filterParams.has_key (filterId):
+        match = None
+
+        # if the master has not been defined, be nice and check if the user has
+        # set the filter-value by it's gnue_id. This will give us an apropriate
+        # master-value since gnue_id *must* be unique.
+        if master is not None and not result.has_key (master):
+          if self.__filterParams [filterId].has_key ('gnue_id'):
+            searchId = self.__filterParams [filterId]['gnue_id']
+            for (mk, vsec) in values.items ():
+              for cfield in vsec:
+                if cfield.has_key ('gnue_id') and \
+                    cfield ['gnue_id'] == searchId:
+                  match = searchId
+                  # result [master] = mk
+                  break
+        else:
+          masterKey = master is not None and result [master] or None
+
+          for item in values [masterKey]:
+            for (field, fieldValue) in self.__filterParams [filterId].items ():
+              if item.has_key (field) and item [field] == fieldValue:
+                match = item ['gnue_id']
+                break
+
+        if match is None:
+          raise StartupError, \
+              u_("No filter '%s' found matching the requested values") \
+              % fNames [filterId]
+
+        result [filterId] = match
+
+    gDebug (1, "Filters: %s" % result)
+    return result
+
+      
+  # ---------------------------------------------------------------------------
+  # Create a list of classes to be exported
+  # ---------------------------------------------------------------------------
+
+  def __createClassList (self, args):
+    """
+    This function creates a sequence of classnames to be dumped. This sequence
+    is in a proper order so no constraint-violations should occur.
+
+    @param args: list of classnames or modulenames to be exported
+    """
+
+    if not len (args):
+      if self.__useFilter:
+        for filterId in self.filters.keys ():
+          filterClass = self.sm.classes.find (filterId)
+          if not filterClass.fullName in args:
+            args.append (filterClass.fullName)
+
+      else:
+        for c in self.sm.classes.values ():
+          if c.module.fullName == 'gnue':
+            continue
+          
+          args.append (c.fullName)
+
+    if self.OPTIONS ['system']:
+      for c in self.sm.classes.values ():
+        if c.module.fullName == 'gnue' and not c.fullName in args:
+          args.append (c.fullName)
+
+    self.__classes = {}
+    self.__fishes  = {}
+
+    for item in args:
+      self.__addClass (item)
+
+    self.__refDict = copy.deepcopy (self.__classes)
+
+    result = []
+    add = self.__shrinkList (self.__classes, CircularReferenceError)
+    while len (add):
+      result.extend (add)
+      add = self.__shrinkList (self.__classes, CircularReferenceError)
+
+    return result
+
+
+
+  # ---------------------------------------------------------------------------
+  # add a class to the classlist and iterate over all references
+  # ---------------------------------------------------------------------------
+
+  def __addClass (self, className):
+    """
+    This function adds a class to the list of classes respecting all
+    dependencies given by class-references.
+    """
+
+    cDef = self.sm.classes [className]
+
+    # every class has a sequence of master-classes
+    if not self.__classes.has_key (className):
+      self.__classes [className] = []
+
+    # now add all master-classes to the dependancy list
+    for p in cDef.properties.values ():
+      if p.isReference:
+        refClass = p.referencedClass.fullName
+
+        if refClass == className:
+          if not self.__fishes.has_key (className):
+            self.__fishes [className] = []
+          self.__fishes [className].append (p.fullName)
+
+        elif not refClass in self.__classes [className]:
+          self.__classes [className].append (refClass)
+
+        if not self.__classes.has_key (refClass):
+          self.__addClass (refClass)
+
+    if not self.OPTIONS ['include-details']:
+      return
+
+    # if 'include-details' is set, we've to add all detail-classes of the
+    # current class.
+    for cClass in self.sm.classes.values ():
+      for p in cClass.properties.values ():
+        if p.isReference and p.referencedClass.gnue_id == cDef.gnue_id:
+          if not self.__classes.has_key (cClass.fullName):
+            self.__addClass (cClass.fullName)
+
+
+
+  # ---------------------------------------------------------------------------
+  # Return all items from the dictionary which have no dependencies
+  # ---------------------------------------------------------------------------
+
+  def __shrinkList (self, dataDict, circularError, *args):
+    """
+    This function returns a sequence of all keys without any dependencies.
+    If no such items were found but there are still entries in the dictionary
+    a CircularReferenceError will be raised.
+
+    @param dataDict: dictionary to extract items from. The values are sequences
+        with keys which are referencing to an item
+    @param circularError: exception class which will be raised if there are
+        circular references
+    @return: sequence of all keys which do not have any dependency
+    """
+
+    result = []
+
+    for (key, references) in dataDict.items ():
+      if not len (references):
+        # if an item has no dependencies add it to the result
+        result.append (key)
+
+        # remove it from all other entries it is referred to
+        for ref in dataDict.values ():
+          if key in ref:
+            ref.remove (key)
+
+        # and finally remove it from the dictionary
+        del dataDict [key]
+
+    # if no entry without a dependency was found, but there are still entries
+    # in the dictionary, they *must* have circular references
+    if not len (result) and len (dataDict.keys ()):
+      raise circularError, args
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Create a dictionary with conditions for classes
+  # ---------------------------------------------------------------------------
+
+  def __createConditionDicts (self):
+    """
+    This function creates a dictionary with sequences of condition-tuples for
+    all classes where every tuple represents an 'equal'-condition. To get the
+    final condition per class all tuples will be AND-connected.
+
+    Such a tuple has the following form:
+    (source-relation, souce-item, destination-relation, destination-item)
+
+    If destination-relation is None, destination-item is a field-value
+    otherwise it's a field-name. 
+    Examples: (foo, bar, foobar, barbaz) means foo.bar = foobar.barbaz
+              (foo, bar, None, barbaz)   means foo.bar = barbaz
+
+    @return: dictionary with conditions
+    """
+
+    result = {}
+
+    if not self.__useFilter:
+      return result
+
+    for className in self.exports:
+      classdef = self.sm.classes [className]
+
+      cond = []
+
+      # if a class is given as a filter create a direct condition
+      if self.filters.has_key (classdef.gnue_id):
+        cond = [(className, 'gnue_id', None, self.filters [classdef.gnue_id])]
+
+      else:
+        for p in classdef.properties.values ():
+          # add a condition if a reference property points to a class which has
+          # a condition already set. Otherwise there's no need to filter the
+          # class
+          if not p.isReference or \
+              not result.has_key (p.referencedClass.fullName):
+            continue
+
+          refClass   = p.referencedClass.fullName
+          refClassId = p.referencedClass.gnue_id
+
+          if self.filters.has_key (refClassId):
+            dstRel  = None
+            dstItem = self.filters [refClassId]
+
+          else:
+            dstRel  = refClass
+            dstItem = 'gnue_id'
+
+            # if the reference is not a fishhook import the master's condition
+            if refClass != className:
+              cond.extend (result [refClass])
+
+          cond.append ((className, p.fullName, dstRel, dstItem))
+
+      # we do *not* add empty conditions to the dictionary
+      if len (cond):
+        result [className] = cond
+
+    gDebug (1, "Condition-Dict: %s" % result)
+    return result
+
+
+
+
+  # ---------------------------------------------------------------------------
+  # Create a new datasource for a table using a given field list
+  # ---------------------------------------------------------------------------
+
+  def __openSource (self, classdef, fieldList):
+    """
+    This function creates a new datasource for a table using a list of fields.
+    @param classdef: classdefinition to prepare a datasource for
+    @param fieldList: sequence with fieldnames
+
+    @return: tuple with the datasource and it's field list
+    """
+
+    className = classdef.fullName
+    alias     = {classdef.table: ""}
+
+    # prepare a dictionary with aliases for all tables needed
+    if self.conditions.has_key (className):
+      alias [classdef.table] = 't0'
+      index = 1
+      for (srcrel, srcitem, dstrel, dstitem) in self.conditions [className]:
+        if not alias.has_key (self.sm.classes [srcrel].table):
+          alias [self.sm.classes [srcrel].table] = "t%d" % index
+          index += 1
+
+        if dstrel is not None and \
+            not alias.has_key (self.sm.classes [dstrel].table):
+          alias [self.sm.classes [dstrel].table] = "t%d" % index
+          index += 1
+
+    # make sure the list of tables is sorted by alias
+    tl = [(al, name) for (name, al) in alias.items ()]
+    tl.sort ()
+    table = string.join (["%s %s" % (t, a.strip ()) for (a, t) in tl], ", ")
+
+    # add alias information to the field list
+    if len (alias [classdef.table]):
+      fieldList = ["%s.%s" % (alias [classdef.table], f) for f in fieldList 
[:]]
+
+    # create a condition tree for joins and filters
+    conditions = None
+    if self.conditions.has_key (className):
+      for (srcrel, srcitem, dstrel, dstitem) in self.conditions [className]:
+        sValue = "%s.%s" % (alias [self.sm.classes [srcrel].table], srcitem)
+        if dstrel is None:
+          dType  = 'const'
+          dValue = dstitem
+        else:
+          dType  = 'field'
+          dValue = "%s.%s" % (alias [self.sm.classes [dstrel].table], dstitem)
+
+        c = GConditions.buildTreeFromList ( \
+            ['eq', ['field', sValue], [dType, dValue]])
+
+        if conditions is not None:
+          conditions = GConditions.combineConditions (conditions, c)
+        else:
+          conditions = c
+
+    result = GDataSource.DataSourceWrapper (connections = self.connections,
+        attributes = {'name'      : "dts_%s" % table,
+                      'database'  : self.sm._internalSession.database,
+                      'table'     : table,
+                      'primarykey': 'gnue_id'},
+        fields = fieldList, unicodeMode = True)
+    
+    if conditions is not None:
+      result.setCondition (conditions)
+
+    return (result, fieldList)
+
+
+
+
 # =============================================================================
 # Main program
 # =============================================================================





reply via email to

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