commit-gnue
[Top][All Lists]
Advanced

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

[gnue] r7610 - in trunk/gnue-common: scripts src src/datasources src/dat


From: johannes
Subject: [gnue] r7610 - in trunk/gnue-common: scripts src src/datasources src/datasources/drivers/Base src/datasources/drivers/DBSIG2 src/datasources/drivers/adodbapi src/datasources/drivers/appserver src/datasources/drivers/interbase src/datasources/drivers/interbase/interbase src/datasources/drivers/maxdb src/datasources/drivers/maxdb/maxdb src/datasources/drivers/mysql src/datasources/drivers/mysql/mysql src/datasources/drivers/oracle src/datasources/drivers/postgresql src/datasources/drivers/postgresql/Base src/datasources/drivers/sqlite src/datasources/drivers/sqlite/sqlite src/definitions
Date: Fri, 17 Jun 2005 07:32:35 -0500 (CDT)

Author: johannes
Date: 2005-06-17 07:32:33 -0500 (Fri, 17 Jun 2005)
New Revision: 7610

Removed:
   trunk/gnue-common/src/datasources/drivers/Base/Schema/
   trunk/gnue-common/src/datasources/drivers/DBSIG2/Schema/
   trunk/gnue-common/src/datasources/drivers/adodbapi/Schema/
   trunk/gnue-common/src/datasources/drivers/appserver/Schema/
   trunk/gnue-common/src/datasources/drivers/interbase/Schema/
   trunk/gnue-common/src/datasources/drivers/maxdb/Schema/
   trunk/gnue-common/src/datasources/drivers/mysql/Schema/
   trunk/gnue-common/src/datasources/drivers/oracle/Schema/
   trunk/gnue-common/src/datasources/drivers/postgresql/Schema/
   trunk/gnue-common/src/datasources/drivers/sqlite/Schema/
   trunk/gnue-common/src/schema/
Modified:
   trunk/gnue-common/scripts/gnue-schema
   trunk/gnue-common/src/datasources/GDataSource.py
   trunk/gnue-common/src/datasources/GSchema.py
   trunk/gnue-common/src/datasources/drivers/Base/Behavior.py
   trunk/gnue-common/src/datasources/drivers/Base/Connection.py
   trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
   trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
   trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
   trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
   trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py
   trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
   trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
   trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
   trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
   trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
   trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
   trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
   trunk/gnue-common/src/definitions/GObjects.py
   trunk/gnue-common/src/definitions/GParserHelpers.py
Log:
Implemented writeSchema (), removed old Schema/Creation/*


Modified: trunk/gnue-common/scripts/gnue-schema
===================================================================
--- trunk/gnue-common/scripts/gnue-schema       2005-06-17 12:17:51 UTC (rev 
7609)
+++ trunk/gnue-common/scripts/gnue-schema       2005-06-17 12:32:33 UTC (rev 
7610)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2001-2003 Free Software Foundation
+# Copyright 2001-2005 Free Software Foundation
 #
 # This file is part of GNU Enterprise.
 #
@@ -20,12 +20,14 @@
 # - Suite 330, Boston, MA 02111-1307, USA.
 # 
 # $Id$
-
-import os, sys
-if hasattr(sys, 'frozen'):
-  sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0])))
 
-from gnue.common.schema.scripter.Scripter import Scripter
+import os
+import sys
 
+if hasattr (sys, 'frozen'):
+  sys.path.append (os.path.abspath (os.path.dirname (sys.argv[0])))
+
+from gnue.common.datasources.readgsd import gsdClient
+
 if __name__ == "__main__":
-  Scripter ().run ()
+  gsdClient ().run ()

Modified: trunk/gnue-common/src/datasources/GDataSource.py
===================================================================
--- trunk/gnue-common/src/datasources/GDataSource.py    2005-06-17 12:17:51 UTC 
(rev 7609)
+++ trunk/gnue-common/src/datasources/GDataSource.py    2005-06-17 12:32:33 UTC 
(rev 7610)
@@ -1068,13 +1068,7 @@
     self._datasourceDictionary={}
     self._toplevelParent = self._type
 
-  def getIntrospector (self):
-    return self._connection.behavior
 
-  def getSchemaCreator (self):
-    return self._connection.getSchemaCreator ()
-
-
 # =============================================================================
 # Load AppServer specific resources
 # =============================================================================

Modified: trunk/gnue-common/src/datasources/GSchema.py
===================================================================
--- trunk/gnue-common/src/datasources/GSchema.py        2005-06-17 12:17:51 UTC 
(rev 7609)
+++ trunk/gnue-common/src/datasources/GSchema.py        2005-06-17 12:32:33 UTC 
(rev 7610)
@@ -21,11 +21,9 @@
 #
 # $Id$
 
-import sets
-import copy
-
-from gnue.common.definitions.GObjects import GObj
+from gnue.common.definitions.GObjects import GObj, GUndividedCollection
 from gnue.common.definitions.GRootObj import GRootObj
+from gnue.common.definitions.GParserHelpers import GLeafNode
 from gnue.common.formatting import GTypecast
 from gnue.common.definitions import GParser
 
@@ -42,210 +40,13 @@
   # Constructor
   # ---------------------------------------------------------------------------
 
-  def __init__ (self, parent, objType, leafNode = False, **kwargs):
+  def __init__ (self, parent, objType, **kwargs):
 
-    global xmlElements
-
     GObj.__init__ (self, parent, objType)
-    self.isLeafNode = leafNode
+    self.buildObject (**kwargs)
 
-    # All remaining keyword arguments are incorporated as own attributes.
-    self.__dict__.update (kwargs)
 
-    # Get the sequence of 'assignable' members
-    if xmlElements is None:
-      xmlElements = getXMLelements ()
-    okey = objType [2:].lower ()
-    if okey in xmlElements:
-      self.MEMBERS = xmlElements [okey].get ('Attributes', {}).keys ()
-    else:
-      self.MEMBERS = []
-
-
-  # ---------------------------------------------------------------------------
-  # Assign a given set of attributes from another instance
-  # ---------------------------------------------------------------------------
-
-  def assign (self, source, recursive = False):
-    """
-    """
-
-    if self.__class__ != source.__class__:
-      raise AssignmentTypeError, (self, source)
-
-    for item in self.MEMBERS:
-      if hasattr (source, item):
-        setattr (self, item, getattr (source, item))
-
-    if recursive:
-      self._children = []
-
-      for child in source._children:
-        new = child.__class__ (None)
-        self.addChild (new)
-        new.setParent (self)
-
-        new.assign (child, recursive)
-    
-
-  def _setAction (self, obj, newAction):
-    obj._action = newAction
-
-
-  # ---------------------------------------------------------------------------
-  #
-  # ---------------------------------------------------------------------------
-
-  def diff (self, goal, maxIdLength = None):
-
-    result = None
-
-    mine   = {}
-    others = {}
-
-    # Build a mapping of our children
-    for child in self._children:
-      mine [child._id_ (maxIdLength)] = child
-
-    # find the counterpart of this instance
-    buddy = goal.findChildOfType (self._type, True, True)
-
-    # If there is no such object, all items in self are 'old' then
-    if buddy is None:
-      pass
-    else:
-      for child in buddy._children:
-        others [child._id_ (maxIdLength)] = child
-
-    # Find out new and changed items
-    for (key, item) in others.items ():
-      childDiff = None
-
-      if not key in mine:
-        if item._children or item.isLeafNode:
-          childDiff = item.__class__ (None)
-          childDiff.assign (item, True)
-          childDiff.walk (self._setAction, "add")
-
-      else:
-        # we need to find out wether the instances are changed then
-        childDiff = mine [key].diff (item, maxIdLength)
-        if childDiff is not None:
-          childDiff._action = "change"
-
-      if childDiff is not None:
-        if result is None:
-          result = self.__class__ (None)
-          result.assign (self)
-
-        result.addChild (childDiff)
-        childDiff.setParent (result)
-
-    # Finally find out all 'obsolete' ones
-    for (key, item) in mine.items ():
-      if not key in others:
-        if result is None:
-          result = self.__class__ (None)
-          result.assign (self)
-
-        child = item.__class__ (None)
-        child.assign (item, True)
-        child.walk (self._setAction, "remove")
-
-        result.addChild (child)
-        child.setParent (result)
-
-    if result is not None:
-      result._action = "change"
-
-    return result
-
-
-  # ---------------------------------------------------------------------------
-  # Return a 'unique' and 'compareable' representation of an instance
-  # ---------------------------------------------------------------------------
-
-  def _id_ (self, maxIdLength = None):
-
-    if hasattr (self, 'name'):
-      result = self.name.lower ()
-      if maxIdLength is not None:
-        result = result [:maxIdLength]
-    else:
-      result = self._type
-
-    return result
-
-
-  # ---------------------------------------------------------------------------
-  # Merge another object tree with this tree
-  # ---------------------------------------------------------------------------
-
-  def merge (self, other):
-    """
-    Incorporate all subtrees from the given object tree of this instances type.
-    """
-
-    # First find objects of the same type in the other tree
-    candidates = other.findChildrenOfType (self._type, True, True)
-
-    # We keep a mapping of all our children
-    mine = {}
-    for mc in self._children:
-      mine [mc._id_ ()] = mc
-
-    # Iterate over all elements in the other tree having the same type
-    for item in candidates:
-      # and observe all their children ...
-      for otherChild in item._children:
-        # ... wether we have to start a recursive merge ...
-        if otherChild._id_ () in mine:
-          mine [otherChild._id_ ()].merge (otherChild)
-        # ... or we can copy the subtree
-        else:
-          new = otherChild.__class__ (self)
-          new.assign (otherChild, True)
-
-
 # =============================================================================
-#
-# =============================================================================
-
-class GSImmutableCollection (GSObject):
-
-  # ---------------------------------------------------------------------------
-  #
-  # ---------------------------------------------------------------------------
-
-  def diff (self, goal, maxIdLength = None):
-
-    result = GSObject.diff (self, goal, maxIdLength)
-
-    if result is not None:
-      for item in result._children [:]:
-        # We cannot change a child of an immutable collection directly, instead
-        # we remove the original and add the changed one.
-        if item._action == 'change':
-          result._children.remove (item)
-
-          for old in self._children:
-            if old._id_ (maxIdLength) == item._id_ (maxIdLength):
-              add = old.__class__ (result)
-              add.assign (old, True)
-              add.walk (self._setAction, "remove")
-              break
-
-          for new in goal._children:
-            if new._id_ (maxIdLength) == item._id_ (maxIdLength):
-              add = new.__class__ (result)
-              add.assign (new, True)
-              add.walk (self._setAction, "add")
-              break
-
-    return result
-
-
-# =============================================================================
 # This class implements the object tree for schema definitions
 # =============================================================================
 
@@ -256,6 +57,7 @@
     GRootObj.__init__(self, 'schema', getXMLelements, __name__)
     GSObject.__init__(self, parent, 'GSSchema')
 
+# =============================================================================
 
 class GSTables (GSObject):
   def __init__(self, parent, **params):
@@ -266,6 +68,8 @@
     return "%s" % self.type
 
 
+# =============================================================================
+
 class GSTable (GSObject):
   def __init__(self, parent, **params):
     GSObject.__init__(self, parent, 'GSTable', **params)
@@ -277,225 +81,132 @@
       else:
         yield field
 
+# =============================================================================
+
 class GSFields (GSObject):
   def __init__(self, parent, **params):
     GSObject.__init__(self, parent, 'GSFields', **params)
 
+# =============================================================================
 
-class GSField (GSObject):
+class GSField (GSObject, GLeafNode):
   def __init__(self, parent, **params):
-    GSObject.__init__(self, parent, 'GSField', True, **params)
+    GSObject.__init__(self, parent, 'GSField', **params)
 
-class GSPrimaryKey (GSImmutableCollection):
-  def __init__ (self, parent, **params):
-    GSImmutableCollection.__init__(self, parent, 'GSPrimaryKey', **params)
+# =============================================================================
 
-class GSPKField (GSObject):
+class GSPrimaryKey (GUndividedCollection):
   def __init__ (self, parent, **params):
-    GSObject.__init__(self, parent, 'GSPKField', True, **params)
+    GUndividedCollection.__init__(self, parent, 'GSPrimaryKey', **params)
 
-class GSConstraints (GSImmutableCollection):
-  def __init__ (self, parent, **params):
-    GSImmutableCollection.__init__(self, parent, 'GSConstraints', **params)
 
-class GSConstraint(GSObject):
-  def __init__ (self, parent, **params):
-    GSObject.__init__ (self, parent, 'GSConstraint', **params)
-    self.__tables = None
+# =============================================================================
 
-class GSConstraintField (GSObject):
+class GSPKField (GSObject, GLeafNode):
   def __init__ (self, parent, **params):
-    GSObject.__init__(self, parent, 'GSConstraintField', True, **params)
+    GSObject.__init__(self, parent, 'GSPKField', **params)
 
-class GSConstraintRef (GSObject):
-  def __init__ (self, parent, **params):
-    GSObject.__init__(self, parent, 'GSConstraintRef', True, **params)
 
-class GSIndexes (GSImmutableCollection):
-  def __init__ (self, parent, **params):
-    GSImmutableCollection.__init__(self, parent, 'GSIndexes', **params)
+# =============================================================================
 
-class GSIndex (GSObject):
+class GSConstraints (GUndividedCollection):
   def __init__ (self, parent, **params):
-    GSObject.__init__(self, parent, 'GSIndex', **params)
+    GUndividedCollection.__init__(self, parent, 'GSConstraints', **params)
 
-class GSIndexField (GSObject):
-  def __init__ (self, parent, **params):
-    GSObject.__init__(self, parent, 'GSIndexField', True, **params)
 
+# =============================================================================
 
-class GSData(GSObject):
-  def __init__(self, parent):
-    GSObject.__init__(self, parent, 'GSData')
+class GSForeignKey (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSForeignKey', **params)
 
-class GSTableData(GSObject):
-  def __init__(self, parent):
-    GSObject.__init__(self, parent, 'GSTableData')
 
-class GSRows(GSObject):
-  def __init__(self, parent):
-    GSObject.__init__(self, parent, 'GSRows')
-
-class GSRow(GSObject):
-  def __init__(self, parent):
-    GSObject.__init__(self, parent, '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, 'GSValue', True)
-    self.dataType  = None
-    self.length    = None
-    self.precision = None
-    self.value     = None
+class GSFKField (GSObject, GLeafNode):
+  def __init__ (self, parent, **params):
+    GSObject.__init__(self, parent, 'GSFKField', **params)
 
-    self._inits.append (self._validate)
 
+# =============================================================================
 
-  def _validate (self):
-    if hasattr (self, "field"):
-      column = self._findColumn (self.field)
-    else:
-      column = self._findColumn (self._getIndex ())
+class GSIndexes (GUndividedCollection):
+  def __init__ (self, parent, **params):
+    GUndividedCollection.__init__(self, parent, 'GSIndexes', **params)
 
-    try:
-      self.value = valueToNative (self, column)
 
-    except Exception, message:
-      self.value = None
+# =============================================================================
 
-      print message
-      setErrorFlag (self)
+class GSIndex (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__(self, parent, 'GSIndex', **params)
 
 
-  # ---------------------------------------------------------------------------
-  # 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)
+class GSIndexField (GSObject, GLeafNode):
+  def __init__ (self, parent, **params):
+    GSObject.__init__(self, parent, 'GSIndexField', **params)
 
-    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
-    """
-    parent = self.getParent ()
-    if parent is not None:
-      for index in range (0, len (parent._children)):
-        if parent._children [index] == self:
-          return index
+class GSData (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSData', **params)
 
-    raise errors.ApplicationError, \
-        u_("GSD-Error: can't find myself in the XML tree?!")
 
+# =============================================================================
 
+class GSTableData (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSTableData', **params)
 
-class GSDescription(GSObject):
-  def __init__(self, parent):
-    GSObject.__init__(self, parent, 'GSDescription', True)
 
-
-
 # =============================================================================
-# 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, "GSDefinition")
-    self.columns = {}
-    self.collist = []
-    self._inits.append (self.__buildColumnDict)
+class GSRows (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSRows', **params)
 
-  def __buildColumnDict (self):
-    self.collist = self.findChildrenOfType ('GSColumn')
-    self.columns = {}
+  # ---------------------------------------------------------------------------
+  # Merge a rows collection with another one
+  # ---------------------------------------------------------------------------
 
-    for col in self.collist:
-      self.columns [col.field] = col
-
-
-  def getColumn (self, fieldSpec):
+  def merge (self, other, maxIdLength = None):
     """
-    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.
+    Merge all rows of another rows collection into this one. Since we cannot
+    determine a primary key here we have no chance to detect duplicate rows.
+    That's why we just copy all of the others' rows.
     """
-    if isinstance (fieldSpec, types.IntType) and fieldSpec < len 
(self.collist):
-      return self.collist [fieldSpec]
 
-    elif self.columns.has_key (fieldSpec):
-      return self.columns [fieldSpec]
+    for row in other.findChildrenOfType ('GSRow', False, True):
+      new = GSRow (self)
+      new.assign (row, True)
 
-    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
-  'precision'.
-  """
-  def __init__ (self, parent):
-    GSObject.__init__ (self, parent, "GSColumn", True)
-    self.typename  = None
-    self.length    = None
-    self.precision = None
-    self._inits.append (self._validate)
+class GSRow (GSObject):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSRow', **params)
 
-  def _validate (self):
-    (self.typename, self.length, self.precision) = verifyDataType (self)
 
+# =============================================================================
 
-# -----------------------------------------------------------------------------
-# recursively set an error flag in a object hierarchy
-# -----------------------------------------------------------------------------
+class GSValue (GSObject, GLeafNode):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSValue', **params)
 
-def setErrorFlag (aObject):
-  """
-  This function sets the property 'foundErrors' in an object and all its
-  parents.
-  """
-  if aObject is not None:
-    aObject.foundErrors = True
-    setErrorFlag (aObject.getParent ())
 
+# =============================================================================
 
+class GSDescription (GSObject, GLeafNode):
+  def __init__ (self, parent, **params):
+    GSObject.__init__ (self, parent, 'GSDescription', **params)
+
+
 # =============================================================================
 # load an XML object tree from a given stream and return it's root object
 # =============================================================================
@@ -615,7 +326,7 @@
             'name':        {
                'Required': 1,
                'Typecast': GTypecast.name } },
-         'ParentTags':  ('table',) },
+         'ParentTags':  ('table', 'tabledata') },
 
       'pkfield':   {
          'BaseClass': GSPKField,
@@ -630,34 +341,26 @@
          'SingleInstance': 1,
          'ParentTags':  ('table',) },
 
-      'constraint':    {
-         'BaseClass': GSConstraint,
+      'foreignkey':    {
+         'BaseClass': GSForeignKey,
          'Attributes': {
             'name': {
                'Required': 1,
                'Typecast': GTypecast.name },
-            'type': {
+            'references': {
                'Typecast': GTypecast.name } },
          'ParentTags':  ('constraints',) },
 
-      'constraintfield':   {
-         'BaseClass': GSConstraintField,
+      'fkfield':   {
+         'BaseClass': GSFKField,
          'Attributes': {
             'name':        {
                'Required': 1,
-               'Typecast': GTypecast.name } },
-         'ParentTags':  ('constraint',) },
-
-      'constraintref':   {
-         'BaseClass': GSConstraintRef,
-         'Attributes': {
-            'name':        {
-               'Required': 1,
                'Typecast': GTypecast.name },
-             'table':        {
+            'references':        {
                'Required': 1,
                'Typecast': GTypecast.name } },
-         'ParentTags':  ('constraint',) },
+         'ParentTags':  ('foreignkey',) },
 
       'indexes':   {
          'BaseClass': GSIndexes,
@@ -699,26 +402,6 @@
                'Typecast': GTypecast.name } },
          'ParentTags':  ('data',) },
 
-      'definition': {
-        'BaseClass': GSDefinition,
-        'SingleInstance': True,
-        'ParentTags': ('tabledata',) },
-
-      'column': {
-        'BaseClass': GSColumn,
-        'Attributes': {
-          'field': {
-            'Required': True,
-            'Typecast': GTypecast.name },
-          'type': {
-            'Required': True,
-            'Typecast': GTypecast.name },
-          'key': {
-            'Typecast': GTypecast.boolean,
-            'Default' : False},
-          },
-        'ParentTags': ('definition',)},
-
       'rows':   {
          'BaseClass': GSRows,
          'SingleInstance': 1,
@@ -738,10 +421,6 @@
                'Required': 0,
                'Typecast': GTypecast.name,
                'Default':  'text' },
-            'key': {
-               'Required': 0,
-               'Typecast': GTypecast.boolean,
-               'Default' : 0}
             },
          'ParentTags':  ('row',),
          'MixedContent': 1,
@@ -773,5 +452,3 @@
 
     GParser.xmlHandler.__init__(self)
     self.xmlElements = getXMLelements ()
-
-

Modified: trunk/gnue-common/src/datasources/drivers/Base/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/Behavior.py  2005-06-17 
12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/Base/Behavior.py  2005-06-17 
12:32:33 UTC (rev 7610)
@@ -83,6 +83,9 @@
     """
 
     result = GSchema.GSSchema ()
+    author = self.__module__.replace ('gnue.common.datasources.drivers.', '')
+    title  = u_("DB-Export of %s") % self.__connection.name
+    result.buildAndInitObject (**{'author': author, 'title': title})
 
     self._readSchema_ (result)
 
@@ -93,26 +96,28 @@
   # Update the current connection's schema with the given schema
   # ---------------------------------------------------------------------------
 
-  def writeSchema (self, schema):
+  def writeSchema (self, schema, simulation = False):
     """
     Generate a command sequence to integrate the given schema tree into the
     connection's current schema.
 
     @param schema: GSchema object tree to be integrated in the connection's
         current schema
+    @param simulation: if True, do not create the schema. Instead only the code
+        should be generated.
 
     @return: sequence of statements to be executed on the connection in order
         to create/update the schema
     """
 
     self._current = self.readSchema ()
-    self._diff    = current.diff (schema, self._maxIdLength)
+    self._diff    = self._current.diff (schema, self._maxIdLength)
     self._new     = schema
 
     self._lookups  = self.__getLookups (self._current)
     self._elements = {}
 
-    return self._writeSchema_ (self._current, self._new, self._diff)
+    return self._writeSchema_ (self._current, self._new, self._diff, 
simulation)
 
 
   # ---------------------------------------------------------------------------
@@ -194,7 +199,7 @@
   # Create code for merging the backend's schema to fit the given tree
   # ---------------------------------------------------------------------------
 
-  def _writeSchema_ (self, current, new, diff):
+  def _writeSchema_ (self, current, new, diff, simulation = False):
 
     raise NotImplementedError
 
@@ -302,7 +307,7 @@
   def __getLookups (self, schema):
 
     result = {}.fromkeys (["CONSTRAINT_%s" % c.name for c in \
-                       schema.findChildrenOfType ('GSConstraint', False, 
True)])
+                      schema.findChildrenOfType ('GSForeignKey', False, True)])
     result.update ({}.fromkeys (["INDEX_%s" % i.name for i in \
-                       schema.findChildrenOfType ('GSIndex', False, True)]))
+                      schema.findChildrenOfType ('GSIndex', False, True)]))
     return result

Modified: trunk/gnue-common/src/datasources/drivers/Base/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/Connection.py        
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/Base/Connection.py        
2005-06-17 12:32:33 UTC (rev 7610)
@@ -22,7 +22,6 @@
 # $Id$
 
 import copy
-import string
 
 from gnue.common.apps import GDebug
 
@@ -72,7 +71,7 @@
     self.name       = name
     self.parameters = parameters
     self.__pending  = False
-    self.behavior   = self._getBehavior ()
+    self.behavior   = self._getBehavior_ ()
 
 
   # ---------------------------------------------------------------------------
@@ -313,169 +312,6 @@
 
 
   # ---------------------------------------------------------------------------
-  # Create a new instance of the associated schema creator
-  # ---------------------------------------------------------------------------
-
-  def getSchemaCreator (self):
-    """
-    Create a new instance of the schema creator associated with this driver or
-    None if no creator is available.
-    """
-
-    if self.defaultCreator:
-      return self.defaultCreator (self)
-    else:
-      return None
-
-
-  # ---------------------------------------------------------------------------
-  # update the schema definition 
-  # ---------------------------------------------------------------------------
-
-  def updateSchema (self, definition, codeOnly = False):
-    """
-    Modify the database schema according to the given definition.
-    
-    @param definition: Sequence of table definitions.
-      See L{Schema.Creation.Creation}.
-    @param codeOnly: If True, only the code will be generated to modify the
-      schema, no actions take place.
-    @return: a tuple of three sequences (prologue, body, epilogue) holding the
-      code to perform all schema modifications needed. These sequences should
-      be executed in this order to successfully create the schema.
-    """
-
-    result = ([], [], [])
-
-    schemaCreator = self.getSchemaCreator ()
-
-    if schemaCreator is None:
-      return result
-
-    try:
-      current       = self.behavior.readSchema ()
-      workingSet    = copy.copy (definition)
-      constraintSet = {}
-
-      # before any actions are performed, validate the given definitions
-      for table in definition:
-        schemaCreator.validate (table)
-
-      # in a first run we remove all constraint definitions from the tables, so
-      # we can add or alter all tables without having troubles with order of
-      # occurence.
-      for table in workingSet:
-        # Do we have already a table with that name?
-        res = None
-        for item in current.findChildrenOfType ('GSTable', False, True):
-          if item.name.lower () == table ['name'].lower ():
-            res = item
-            break
-
-        if res is not None:
-          method = schemaCreator.modifyTable
-          # Please note: we keep existingFields sequence in all lowercase
-          existingFields = [f.name.lower () for f in \
-                               res.findChildrenOfType ('GSField', False, True)]
-
-          # keep only new fields
-          keep = []
-          for field in table ['fields']:
-            if not field ['name'].lower () in existingFields:
-              keep.append (field)
-
-          table ['fields'] = keep
-
-          # on updates of a table we cannot use a primary key
-          if table.has_key ('primarykey'):
-            del table ['primarykey']
-  
-          # keep modified or new indices only
-          if table.has_key ('indices'):
-            keep = []
-
-            # if driver supports index-introspection we'll use it
-            if res.findChildOfType ('GSIndexes') is not None:
-              for index in table ['indices']:
-                oldIndex = None
-                for item in res.findChildrenOfType ('GSIndex', False, True):
-                  if item.name.lower () == index ['name'].lower ():
-                    oldIndex = value
-
-                if oldIndex is None:
-                  keep.append (index)
-                else:
-                  old = [f.lower () for f in \
-                      oldIndex.findChildrenOfType ('GSIndexField', False, 
True)]
-                  new = [f.lower () for f in index ['fields']]
-
-                  if oldIndex.unique != index ['unique'] or old != new:
-                    # make sure the backend has a possibility to remove the old
-                    # index before changing it
-                    if not table.has_key ('old_indices'):
-                      table ['old_indices'] = []
-                    table ['old_indices'].append (index ['name'])
-
-                    keep.append (index)
-            else:
-              # if no index-introspection available we only keep an index, if 
it
-              # has new fields
-              for index in table ['indices']:
-                for field in index ['fields']:
-                  if not field.lower () in existingFields:
-                    # make sure the backend has a possibility to remove the old
-                    # index before changing it
-                    if not table.has_key ('old_indices'):
-                      table ['old_indices'] = []
-                    table ['old_indices'].append (index ['name'])
-
-                    keep.append (index)
-                    break
-
-            table ['indices'] = keep
-
-          # we create a constraint on a table update only if it contains new
-          # fields
-          if table.has_key ('constraints'):
-            keep = []
-
-            for constraint in table ['constraints']:
-              for field in constraint ['fields']:
-                if not field.lower () in existingFields:
-                  keep.append (constraint)
-                  break
-
-            table ['constraints'] = keep
-
-        else:
-          method = schemaCreator.createTable
-
-        if table.has_key ('constraints'):
-          constraintSet [table ['name']] = {'name':        table ['name'],
-                                          'constraints': table ['constraints']}
-          del table ['constraints']
-
-        # before we execute the planned action, have a look if there's still
-        # work to be done
-        perform = table.has_key ('fields') and len (table ['fields'])
-        perform = perform or table.has_key ('primarykey')
-        perform = perform or (table.has_key ('indices') and \
-                              len (table ['indices']))
-
-        if perform:
-          schemaCreator.mergeTuple (result, method (table, codeOnly))
-
-      # on the second run we process all constraints
-      for table in constraintSet.values ():
-        schemaCreator.mergeTuple (result,
-                                schemaCreator.createTable (table, codeOnly))
-      return result
-
-    finally:
-      schemaCreator.close ()
-
-
-  # ---------------------------------------------------------------------------
   # Return the current schema information of the connection's backend
   # ---------------------------------------------------------------------------
 
@@ -497,23 +333,24 @@
   # Write a given schema to the connection's backend
   # ---------------------------------------------------------------------------
 
-  def writeSchema (self, schema, codeOnly = False):
+  def writeSchema (self, schema, simulate = False):
     """
     Update the connection's backend database schema with the given schema
     object tree.
 
     @param schema: GSchema object tree defining the schema to be integrated
-    @param codeOnly: if True, create only the command sequence. No integration
+    @param simulate: if True, create only the command sequence. No integration
         takes place.
 
     @return: command sequence which could be used to integrate the given schema
     """
 
+    commands = []
+
     if self.behavior is not None:
-      commands = self.behavior.writeSchema (schema)
+      commands = self.behavior.writeSchema (schema, simulate)
 
-    else:
-      return []
+    return commands
 
 
   # ---------------------------------------------------------------------------
@@ -712,7 +549,7 @@
 
   # ---------------------------------------------------------------------------
 
-  def _getBehavior (self):
+  def _getBehavior_ (self):
     """
     Create an apropriate behavior instance. If the connection defines a
     '_behavior' attribute this class will be instanciated. If the connection's

Modified: trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py        
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py        
2005-06-17 12:32:33 UTC (rev 7610)
@@ -65,14 +65,17 @@
   # Generate a code sequence to match the requested schema
   # ---------------------------------------------------------------------------
 
-  def _writeSchema_ (self, current, new, diff):
+  def _writeSchema_ (self, current, new, diff, simulation = False):
     """
-    Generate a command sequence to integrate the given schema tree into the
-    connection's current schema.
+    Integrate the given schema into the current connection's schema and return
+    the commands used to achive this. Optionally a simulation for the
+    integration is possible. In that case no real change will take place in the
+    backend.
 
     @param current: GSchema tree with the current schema at the backend
     @param new: GSchema tree with the schema to be achieved
     @param diff: GSchema tree with the differences between current and new
+    @param simulation: if True, only create the command sequence
 
     @return: sequence of commands to be executed for changing the current
         schema into the new one
@@ -89,9 +92,17 @@
         if table._action in ['add', 'change']:
           self.mergeTriple (result, self._createTable_ (table))
 
-    return prolog + main + epilog
+    code = prolog + main + epilog
 
+    if not simulation:
+      for command in code:
+        self.__connection.sql0 (command)
 
+      self.__connection.commit ()
+
+    return code
+
+
   # ---------------------------------------------------------------------------
   # Create the command sequence for table creation or modification
   # ---------------------------------------------------------------------------
@@ -113,7 +124,7 @@
       return result
 
     # Do we have some constraints or indices to be dropped ?
-    for constraint in table.findChildrenOfType ('GSConstraint', False, True):
+    for constraint in table.findChildrenOfType ('GSForeignKey', False, True):
       if constraint._action == "remove":
         csKey = "CONSTRAINT_%s" % constraint.name
         if csKey in self._lookups:
@@ -166,7 +177,7 @@
         self.mergeTriple (result, self._createIndex_ (index))
 
     # build all constraints
-    for constraint in table.findChildrenOfType ('GSConstraint', False, True):
+    for constraint in table.findChildrenOfType ('GSForeignKey', False, True):
       if constraint._action == 'add':
         self.mergeTriple (result, self._createConstraint_ (constraint))
 
@@ -370,7 +381,7 @@
     epilogue, the order of processing related tables does not matter, since all
     new tables are created in the body-part of the code-triples.
 
-    @param constraint: GSConstraint instance to be processed
+    @param constraint: GSForeignKey instance to be processed
     @return: code triple with the command sequences
     """
 
@@ -388,13 +399,13 @@
       elements [csKey] = None
 
     csName  = self._getSafeName_ (constraint.name, "CONSTRAINT")
-    fields  = constraint.findChildrenOfType ('GSConstraintField', False, True)
-    rfields = constraint.findChildrenOfType ('GSConstraintRef', False, True)
+    rfName  = self.shortenName (constraint.references)
+    fields  = constraint.findChildrenOfType ('GSFKField', False, True)
 
     code = u"ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) " \
             "REFERENCES %s (%s)" \
            % (table.name, csName, ", ".join ([f.name for f in fields]),
-              rfields [0].table, ", ".join ([r.name for r in rfields]))
+              rfName, ", ".join ([f.references for f in fields]))
 
     post.append (code)
 
@@ -409,11 +420,12 @@
     """
     Create a command sequence for dropping the given constraint.
 
-    @param constraint: GSConstraint instance to be dropped
+    @param constraint: GSForeignKey instance to be dropped
     @return: command sequence
     """
 
-    return [u"DROP CONSTRAINT %s" % constraint.name]
+    table = constraint.findParentOfType ('GSTable').name
+    return [u"ALTER TABLE %s DROP CONSTRAINT %s" % (table, constraint.name)]
 
 
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py     
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py     
2005-06-17 12:32:33 UTC (rev 7610)
@@ -118,13 +118,12 @@
         if '_' in field.nativetype:
           master = table.findChildOfType ('GSConstraints') or \
                                                   GSchema.GSConstraints (table)
-          constraint = GSchema.GSConstraint (master,
+          constraint = GSchema.GSForeignKey (master,
               name = "fk_%s_%s" % (table.name, field.nativetype),
-              type = 'foreignkey')
+              references = field.nativetype)
 
-          GSchema.GSConstraintField (constraint, name = field.name)
-          GSchema.GSConstraintRef (constraint, name = u"gnue_id",
-                                   table = field.nativetype)
+          GSchema.GSFKField (constraint, name = field.name,
+                                         references = u"gnue_id")
 
 
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py     
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py     
2005-06-17 12:32:33 UTC (rev 7610)
@@ -50,7 +50,7 @@
   _alterMultiple = False
   _maxVarchar    = 10921
   _numbers       = [[(4, 'SMALLINT'), (9, 'INTEGER')], "NUMERIC(%s)",
-                    "NUMERIC (%(length)s,%(scale)s"]
+                    "NUMERIC (%(length)s,%(scale)s)"]
 
 
   # ---------------------------------------------------------------------------
@@ -269,7 +269,7 @@
         else:
           cons = table.findChildOfType ('GSConstraints') or \
                            GSchema.GSConstraints (table)
-          item = GSchema.GSConstraint (cons, name = name, type = 'foreignkey')
+          item = GSchema.GSForeignKey (cons, name = name)
 
         result ["%s.%s" % (tname, index)] = item
 
@@ -332,19 +332,15 @@
             for field in fields [iname]:
               GSchema.GSPKField (constraint, name = field)
           else:
-            for field in fields [iname]:
-              GSchema.GSConstraintField (constraint, name = field)
+            for (field, reffield) in zip (fields [iname], fields [fkey]):
+              GSchema.GSFKField (constraint, name = field,
+                                             references = reffield)
+            update.setdefault (fkey, []).append (constraint)
 
-            for field in fields [fkey]:
-              item = GSchema.GSConstraintRef (constraint, name = field)
+      for (fkey, constraints) in update.items ():
+        for item in constraints:
+          item.references = relmap [fkey]
 
-            update.setdefault (fkey, []).append (item)
-
-      # Finally make sure all constraint reference fields pointing to a table
-      for (fkey, crefs) in update.items ():
-        for item in crefs:
-          item.table = relmap [fkey]
-
     finally:
       cursor.close ()
 

Modified: 
trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py 
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py 
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
 __all__ = ['Connection']
 
 from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.interbase.Schema.Creation.Creation import 
Creation
 from gnue.common.datasources.drivers.interbase import Behavior
 
 
@@ -38,11 +37,10 @@
   """
 
   _drivername = 'kinterbasdb'
+  _behavior   = Behavior.Behavior
 
   _broken_rowcount = True
 
-  defaultCreator  = Creation
-  _behavior       = Behavior.Behavior
 
 
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py 2005-06-17 
12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py 2005-06-17 
12:32:33 UTC (rev 7610)
@@ -320,16 +320,16 @@
         master = table.findChildOfType ('GSConstraints') or \
                                                   GSchema.GSConstraints (table)
         cs = None
-        for item in master.findChildrenOfType ('GSConstraint', False, True):
+        for item in master.findChildrenOfType ('GSForeignKey', False, True):
           if item.name == fkname:
             cs = item
             break
 
         if cs is None:
-          cs = GSchema.GSConstraint (master, name = fkname, type = 
'foreignkey')
+          cs = GSchema.GSForeignKey (master, name = fkname,
+                                             references = reftable)
 
-        GSchema.GSConstraintField (cs, name = cname)
-        GSchema.GSConstraintRef (cs, name = refcol, table = reftable)
+        GSchema.GSFKField (cs, name = cname, references = refcol)
 
     finally:
       cursor.close ()

Modified: trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py 
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py 
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
 __all__ = ['Connection']
 
 from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.maxdb.Schema.Creation.Creation import 
Creation
 from gnue.common.datasources.drivers.maxdb import Behavior
 
 
@@ -38,11 +37,10 @@
   """
 
   _drivername = 'sapdb.dbapi'
+  _behavior   = Behavior.Behavior
 
   _named_as_sequence = True
 
-  _behavior      = Behavior.Behavior
-  defaultCreator = Creation
 
 
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py 
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py 
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
 __all__ = ['Connection']
 
 from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.mysql.Schema.Creation.Creation import 
Creation
 from gnue.common.datasources.drivers.mysql import Behavior
 
 
@@ -38,13 +37,12 @@
   """
 
   _drivername     = 'MySQLdb'
+  _behavior       = Behavior.Behavior
+
   _boolean_true   = 1
   _boolean_false  = 0
 
-  defaultCreator  = Creation
-  _behavior       = Behavior.Behavior
 
-
   # ---------------------------------------------------------------------------
   # Get connection parameters
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py        
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py        
2005-06-17 12:32:33 UTC (rev 7610)
@@ -44,8 +44,23 @@
      'all_view'    : {'type': 'allview',     'name': _('System Views')},
      'all_synonym' : {'type': 'allsynonym',  'name': _('System Synonyms')}}
 
+  _pkPrecision   = 10
+  _maxIdLength   = 31
+  _alterMultiple = False
+  _numbers       = [[], "number (%s)", "number (%(length)s,%(scale)s)"]
 
+
   # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, *args, **kwargs):
+
+    DBSIG2.Behavior.__init__ (self, *args, **kwargs)
+    self._type2native.update ({'datetime': 'date', 'time': 'date'})
+
+
+  # ---------------------------------------------------------------------------
   # Read the current connection's schema
   # ---------------------------------------------------------------------------
 
@@ -154,3 +169,113 @@
 
       finally:
         cursor.close ()
+
+
+  # ---------------------------------------------------------------------------
+  # Create a new database
+  # ---------------------------------------------------------------------------
+
+  def createDatabase (self):
+    """
+    There's no support for creating databases atm, so a NotImplementedError
+    will be raised.
+    """
+
+    raise NotImplementedError
+
+
+  # ---------------------------------------------------------------------------
+  # Handle sepcial defaults
+  # ---------------------------------------------------------------------------
+
+  def _defaultwith_ (self, code, field):
+    """
+    Creates a sequence for 'serials' and set the default for 'timestamps' to
+    'now ()'
+
+    @param code: code-triple to get the result
+    @param field: GSField instance of the field having the default
+    """
+
+    tablename = field.findParentOfType ('GSTable').name
+    if field.defaultwith == 'serial':
+      seq = self._getSequenceName_ (field)
+      code [0].append (u"CREATE SEQUENCE %s MAXVALUE %s NOCYCLE" \
+                       % (seq, "9" * self._pkPrecision))
+
+      body = u"IF :new.%(field)s IS NULL THEN" \
+              " SELECT %(seq)s.nextval INTO :new.%(field)s FROM dual;" \
+              "END IF;" \
+            % {'field': field.name, 'seq': seq}
+
+      self.__addTrigger (tablename, field.name, code, body)
+
+
+    elif field.defaultwith == 'timestamp':
+      if field.type == 'date':
+        sysdate = "TRUNC (sysdate)"
+      else:
+        sysdate = "sysdate"
+
+      body = u"IF :new.%(field)s IS NULL THEN" \
+              " :new.%(field)s := %(date)s;" \
+              "END IF;" \
+            % {'field': field.name,
+               'date' : sysdate}
+
+      self.__addTrigger (tablename, field.name, code, body)
+
+
+  # ---------------------------------------------------------------------------
+  # Create a trigger code and add it to the epilogue of the given code
+  # ---------------------------------------------------------------------------
+
+  def __addTrigger (self, tablename, fieldname, code, body):
+
+    code [2].append (u"CREATE OR REPLACE TRIGGER t__%(table)s_%(field)s_pre"
+           "  BEFORE INSERT ON %(table)s"
+           "  FOR EACH ROW WHEN (new.%(field)s IS NULL)"
+           "  BEGIN %(body)s END; /"
+          % {'table': tablename,
+             'field': fieldname,
+             'body': body})
+
+
+  # ---------------------------------------------------------------------------
+  # String becomes varchar2
+  # ---------------------------------------------------------------------------
+
+  def string (self, field):
+    """
+    Return the native type for a string-field.
+
+    @param field: GSField instance to get a native type for
+    @return: string with the native datatype
+    """
+
+    length = hasattr (field, 'length') and field.length or 99999
+    if length <= 2000:
+      return "varchar2 (%s) % length"
+    else:
+      return "blob"
+
+
+  # ---------------------------------------------------------------------------
+  # There's no native boolean type
+  # ---------------------------------------------------------------------------
+
+  def boolean (self, field):
+    """
+    Return a native data type for a boolean
+
+    @param field: GSField instance to get a native type for
+    @return: string with the native datatype
+    """
+
+    nullable = hasattr (field, 'nullable') and field.nullable or True
+
+    if nullable:
+      return "number (1) CHECK (%(field)s IS NULL OR %(field)s IN (0,1))" \
+          % {'field': field.name}
+    else:
+      return "number (1) CHECK (%s IN (0,1))" % field.name

Modified: 
trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py     
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py     
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,8 +24,6 @@
 __all__ = ['Connection']
 
 from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.postgresql.Schema.Creation.Creation 
import Creation
-
 from gnue.common.datasources.drivers.postgresql import Behavior
 
 
@@ -38,8 +36,6 @@
   Generic Connection class for PostgreSQL databases.
   """
 
-  defaultCreator  = Creation
-
   _rowidField = 'oid'
   _behavior   = Behavior.Behavior
 

Modified: trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py    
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py    
2005-06-17 12:32:33 UTC (rev 7610)
@@ -39,7 +39,7 @@
   _maxIdLength   = 31
   _alterMultiple = False
   _numbers       = [[(4, 'smallint'), (9, 'integer'), (18, 'bigint')],
-                    "numeric (%s,0)", "numberic (%(length)s,%(scale)s)"]
+                    "numeric (%s,0)", "numeric (%(length)s,%(scale)s)"]
 
 
   # ---------------------------------------------------------------------------
@@ -137,7 +137,7 @@
     fields = self.__readFields (tables)
     self.__readDefaults (fields)
     self.__readKeys (tables)
-    self.__readConstraints (tables)
+    self.__readConstraints (tables, fields)
 
 
   # ---------------------------------------------------------------------------
@@ -336,7 +336,7 @@
   # Read all constraints
   # ---------------------------------------------------------------------------
 
-  def __readConstraints (self, tables):
+  def __readConstraints (self, tables, fields):
 
     cmd = u"SELECT conname, conrelid, confrelid, conkey, confkey " \
            "FROM pg_constraint WHERE contype = 'f'"
@@ -344,7 +344,7 @@
     cursor = self.__connection.makecursor (cmd)
     try:
       for (name, relid, fkrel, key, fkey) in cursor.fetchall ():
-        table = tables.get (relid)
+        table   = tables.get (relid)
         fktable = tables.get (fkrel)
 
         # We need both ends of a relation to be a valid constraint
@@ -355,27 +355,18 @@
         if parent is None:
           parent = GSchema.GSConstraints (table)
 
-        constr = GSchema.GSConstraint (parent, name = name, type = 
'foreignkey')
+        constr = GSchema.GSForeignKey (parent, name = name,
+                                               references = fktable.name)
 
-        if isinstance (key, basestring):
-          keyparts = [int (i) - 1 for i in key [1:-1].split (',')]
-        else:
-          keyparts = [int (item) - 1 for item in key]
+        kp  = isinstance (key, basestring) and key [1:-1].split (',') or key
+        fkp = isinstance (fkey, basestring) and fkey [1:-1].split (',') or fkey
 
-        if isinstance (fkey, basestring):
-          fkeyparts = [int (i) - 1 for i in fkey [1:-1].split (',')]
-        else:
-          fkeyparts = [int (item) - 1 for item in fkey]
+        k = [fields ["%s.%s" % (relid, i)].name for i in kp]
+        f = [fields ["%s.%s" % (fkrel, i)].name for i in fkp]
 
-        keyfields = table.findChildrenOfType ('GSField', False, True)
-        for ix in keyparts:
-          GSchema.GSConstraintField (constr, name = keyfields [ix].name)
+        for (name, refname) in zip (k, f):
+          GSchema.GSFKField (constr, name = name, references = refname)
 
-        fkfields  = fktable.findChildrenOfType ('GSField', False, True)
-        for ix in fkeyparts:
-          GSchema.GSConstraintRef (constr, name = fkfields [ix].name,
-                                           table = fktable.name)
-
     finally:
       cursor.close ()
 

Modified: trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py        
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py        
2005-06-17 12:32:33 UTC (rev 7610)
@@ -228,9 +228,9 @@
       attrs ['nativetype'] = nativetype
 
       if length:
-        attrs ['length'] = length
+        attrs ['length'] = int (length)
       if scale:
-        attrs ['precision'] = scale
+        attrs ['precision'] = int (scale)
 
       attrs ['nullable']   = _NOTNULL.match (item) is None
 

Modified: trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py       
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py       
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
 __all__ = ['Connection']
 
 from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.sqlite.Schema.Creation.Creation import 
Creation
 from gnue.common.datasources.drivers.sqlite import Behavior
 
 
@@ -35,15 +34,13 @@
 class Connection (DBSIG2.Connection):
 
   _drivername = 'sqlite'
+  _behavior      = Behavior.Behavior
 
   # SQLite doesn't like boolean type in SQL parameters
   _boolean_true  = 1
   _boolean_false = 0
 
-  defaultCreator = Creation
-  _behavior      = Behavior.Behavior
 
-
   # ---------------------------------------------------------------------------
   # Constructor
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-common/src/definitions/GObjects.py
===================================================================
--- trunk/gnue-common/src/definitions/GObjects.py       2005-06-17 12:17:51 UTC 
(rev 7609)
+++ trunk/gnue-common/src/definitions/GObjects.py       2005-06-17 12:32:33 UTC 
(rev 7610)
@@ -530,3 +530,54 @@
   def getClass(self):
     raise "Virtual method not implemented"
 
+
+# =============================================================================
+# Collection class where the children in a diff won't get divided
+# =============================================================================
+
+class GUndividedCollection (GObj):
+  """
+  """
+
+  # 
----------------------------------------------------------------------------
+  # Constructor
+  # 
----------------------------------------------------------------------------
+
+  def __init__ (self, *args, **kwargs):
+
+    GObj.__init__ (self, *args)
+    self.buildObject (**kwargs)
+
+
+  # 
----------------------------------------------------------------------------
+  # Build a difference-tree to the given object tree
+  # 
----------------------------------------------------------------------------
+
+  def diff (self, goal, maxIdLength):
+
+    result = ParserObj.diff (self, goal, maxIdLength)
+
+    if result is not None:
+      for item in result._children [:]:
+        # We cannot change a child of an immutable collection directly, instead
+        # we remove the original and add the changed one.
+        if item._action == 'change':
+          result._children.remove (item)
+
+          # Add a copy of the 'old' item to be 'removed'
+          for old in self._children:
+            if old._id_ (maxIdLength) == item._id_ (maxIdLength):
+              add = old.__class__ (result)
+              add.assign (old, True)
+              add.walk (self._diffActionWalker_, "remove")
+              break
+
+          # and one copy of the 'new' item to be 'added'
+          for new in goal._children:
+            if new._id_ (maxIdLength) == item._id_ (maxIdLength):
+              add = new.__class__ (result)
+              add.assign (new, True)
+              add.walk (self._diffActionWalker_, "add")
+              break
+
+    return result

Modified: trunk/gnue-common/src/definitions/GParserHelpers.py
===================================================================
--- trunk/gnue-common/src/definitions/GParserHelpers.py 2005-06-17 12:17:51 UTC 
(rev 7609)
+++ trunk/gnue-common/src/definitions/GParserHelpers.py 2005-06-17 12:32:33 UTC 
(rev 7610)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common Library - GParser - Helper classes
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
 #
+# This file is part of GNU Enterprise
+#
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
 # License as published by the Free Software Foundation; either
@@ -16,31 +19,24 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2001-2005 Free Software Foundation
-#
-# FILE:
-# GParserHelpers.py
-#
-# DESCRIPTION:
-# Class that holds GNUe Parser helper classes
-#
-# NOTES:
-#
-# HISTORY:
-#
+# $Id: $
 
-import weakref
-
 from xml.sax import saxutils
 from types import StringType
 
-#
-# Class ParserObj
-#
-# Common initialization for GParser objects
-#
+
+# =============================================================================
+# Base class for GParser objects
+# =============================================================================
+
 class ParserObj:
-  def __init__(self, parent=None, type='_NotSet_'):
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, parent = None, type = '_NotSet_'):
+    
     self._type          = type
     self._children      = []     # The objects contained by this object
     self._attributes    = {}
@@ -50,7 +46,7 @@
     self._xmlnamespaces = {}     # If attributes are namespace-qualified, a map
 
     self.setParent (parent)
-    if parent :
+    if parent:
       parent.addChild (self)
 
 
@@ -66,10 +62,7 @@
     @rtype: any
     """
 
-    if self.__parent is not None:
-      return self.__parent ()
-    else:
-      return None
+    return self.__parent
 
 
   # ---------------------------------------------------------------------------
@@ -83,57 +76,262 @@
     @param newParent: instance to be set as parent
     """
 
-    if newParent is None:
-      self.__parent = None
+    self.__parent = newParent
+
+
+  # ---------------------------------------------------------------------------
+  # Return a compareable id of an object
+  # ---------------------------------------------------------------------------
+
+  def _id_ (self, maxIdLength = None):
+    """
+    Return a compareable and identifying id of an object within a tree. Usually
+    this is it's name (if available) or it's object type (as given in the
+    constructor).
+
+    @param maxIdLength: if not None only return up to maxIdLength characters.
+    @return: id for the instance
+    """
+
+    if hasattr (self, 'name'):
+      result = self.name.lower ()
+      if maxIdLength is not None:
+        result = result [:maxIdLength]
     else:
-      self.__parent = weakref.ref (newParent)
+      result = self._type
 
+    return result
 
-#
-# Class GContent
-#
+
+  # ---------------------------------------------------------------------------
+  # Assign a given set of attributes from another instance
+  # ---------------------------------------------------------------------------
+
+  def assign (self, source, recursive = False):
+    """
+    """
+
+    if self.__class__ != source.__class__:
+      raise AssignmentTypeError, (self, source)
+
+    # Assign everything except the parent and the children
+    for (name, value) in source.__dict__.items ():
+      if name in ['_ParserObj__parent', '_children']:
+        continue
+
+      self.__dict__ [name] = value
+
+    if recursive:
+      self._children = []
+
+      for child in source._children:
+        new = child.__class__ (None)
+        new.assign (child, recursive)
+
+        self.addChild (new)
+        new.setParent (self)
+
+
+  # ---------------------------------------------------------------------------
+  # Merge another object tree with this tree
+  # ---------------------------------------------------------------------------
+
+  def merge (self, other, maxIdLength = None):
+    """
+    Incorporate all subtrees from the given object tree of this instances type.
+    """
+
+    # First find objects of the same type in the other tree
+    candidates = other.findChildrenOfType (self._type, True, True)
+
+    # We keep a mapping of all our children
+    mine = {}
+    for mc in self._children:
+      mine [mc._id_ (maxIdLength)] = mc
+
+    # Iterate over all elements in the other tree having the same type
+    for item in candidates:
+      # and observe all their children ...
+      for otherChild in item._children:
+        # ... wether we have to start a recursive merge ...
+        if otherChild._id_ (maxIdLength) in mine:
+          mine [otherChild._id_ (maxIdLength)].merge (otherChild)
+        # ... or we can copy the subtree
+        else:
+          new = otherChild.__class__ (self)
+          new.assign (otherChild, True)
+
+
+  # ---------------------------------------------------------------------------
+  # Build a difference-tree from two given object trees
+  # ---------------------------------------------------------------------------
+
+  def diff (self, goal, maxIdLength = None):
+    """
+    """
+
+    result = None
+
+    mine   = {}
+    others = {}
+
+    # Build a mapping of our children
+    for child in self._children:
+      mine [child._id_ (maxIdLength)] = child
+
+    # find the counterpart of this instance
+    buddy = goal.findChildOfType (self._type, True, True)
+
+    if buddy is not None:
+      for child in buddy._children:
+        others [child._id_ (maxIdLength)] = child
+
+    # Find out new and changed items
+    for (key, item) in others.items ():
+      childDiff = None
+
+      if not key in mine:
+        if item._children or isinstance (item, GLeafNode):
+          childDiff = item.__class__ (None)
+          childDiff.assign (item, True)
+          childDiff.walk (self._diffActionWalker_, "add")
+
+      else:
+        # we need to find out wether the instances are changed then
+        childDiff = mine [key].diff (item, maxIdLength)
+        if childDiff is not None:
+          childDiff._action = "change"
+
+      if childDiff is not None:
+        if result is None:
+          result = self.__class__ (None)
+          result.assign (self)
+
+        result.addChild (childDiff)
+        childDiff.setParent (result)
+
+    # Finally find out all 'obsolete' ones
+    for (key, item) in mine.items ():
+      if not key in others:
+        if result is None:
+          result = self.__class__ (None)
+          result.assign (self)
+
+        child = item.__class__ (None)
+        child.assign (item, True)
+        child.walk (self._diffActionWalker_, "remove")
+
+        result.addChild (child)
+        child.setParent (result)
+
+    if result is not None:
+      result._action = "change"
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Set the diff-action for a given object
+  # ---------------------------------------------------------------------------
+
+  def _diffActionWalker_ (self, obj, action):
+
+    obj._action = action
+
+
+# =============================================================================
+# Mixin-class for leaf node objects
+# =============================================================================
+
+class GLeafNode:
+  """
+  This is a I{mixin}-class for parser objects which are leaf nodes. This will
+  be a relevant information on building difference-trees between two object
+  trees. To add this class to another class do something like this::
+
+    class Foobar (ParserObj, GLeafNode): ...
+    class Barbaz (SomeOtherClass, GLeafNode): ...
+
+  There is nothing more to do if you want to flag a class as leaf node.
+  """
+
+  pass
+
+
+# =============================================================================
 # Base class for xml content
-#
-class GContent(ParserObj):
+# =============================================================================
 
-  def __init__(self, parent, content):
-    ParserObj.__init__(self, parent, '_content_')
+class GContent (ParserObj):
+
+  # ---------------------------------------------------------------------------
+  # Constructor
+  # ---------------------------------------------------------------------------
+
+  def __init__ (self, parent, content = None):
+
+    ParserObj.__init__ (self, parent, '_content_')
     self._content = content
 
-  def getEscapedContent(self):
-    return saxutils.escape(self._content)
 
-  def getContent(self):
+  # ---------------------------------------------------------------------------
+  # Return the escaped contents
+  # ---------------------------------------------------------------------------
+
+  def getEscapedContent (self):
+
+    return saxutils.escape (self._content)
+
+
+  # ---------------------------------------------------------------------------
+  # Return the contents
+  # ---------------------------------------------------------------------------
+
+  def getContent (self):
+
     return self._content
 
-  def dumpXML(self, lookupDict, treeDump=None, gap=None,
-              escape=1, textEncoding='<locale>', xmlnamespaces={},
-              stripPrefixes = None):
-    if textEncoding=='<locale>':
-      textEncoding=gConfig('textEncoding')
 
-    if type(self._content) == StringType:
-      xmlString = '%s' % unicode(self._content, textEncoding)
+  # ---------------------------------------------------------------------------
+  # Return a xml representation of the object
+  # ---------------------------------------------------------------------------
+
+  def dumpXML (self, lookupDict, treeDump = None, gap = None,
+               escape = 1, textEncoding = '<locale>', xmlnamespaces = {},
+               stripPrefixes = None):
+
+    if textEncoding == '<locale>':
+      textEncoding = gConfig ('textEncoding')
+
+    if type (self._content) == StringType:
+      xmlString = '%s' % unicode (self._content, textEncoding)
     else:
       xmlString = self._content
 
-    if escape:
-      return saxutils.escape(xmlString)
-    else:
-      return xmlString
+    return escape and saxutils.escape (xmlString) or xmlString
 
 
-  def showTree(self, indent=0):
-    print ' '*indent + 'GContent ' + `self._content`
+  # ---------------------------------------------------------------------------
+  # Show a contents element within an (indented) tree
+  # ---------------------------------------------------------------------------
 
-  #def _type(self):
-  #  return "_content_"
+  def showTree (self, indent = 0):
 
-  #
-  # getDescription
-  #
-  # Return a useful description of this object
-  # Used by designer clients
-  #
-  def getDescription(self):
+    print ' ' * indent + 'GContent ' + `self._content`
+
+
+  # ---------------------------------------------------------------------------
+  # Return a useful description of this object (used by designer clients)
+  # ---------------------------------------------------------------------------
+
+  def getDescription (self):
+
     return "(Content)"
+
+
+  # ---------------------------------------------------------------------------
+  # Don't merge contents instances
+  # ---------------------------------------------------------------------------
+
+  def merge (self, other):
+    return





reply via email to

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