commit-gnue
[Top][All Lists]
Advanced

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

[gnue] r7360 - in trunk/gnue-appserver: src tests


From: johannes
Subject: [gnue] r7360 - in trunk/gnue-appserver: src tests
Date: Wed, 13 Apr 2005 09:00:04 -0500 (CDT)

Author: johannes
Date: 2005-04-13 09:00:02 -0500 (Wed, 13 Apr 2005)
New Revision: 7360

Modified:
   trunk/gnue-appserver/src/data.py
   trunk/gnue-appserver/src/geasInstance.py
   trunk/gnue-appserver/src/geasRpcServer.py
   trunk/gnue-appserver/src/repository.py
   trunk/gnue-appserver/tests/data.py
Log:
Full support of fish-hooks, so order of inserts and deletes doesn't matter


Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py    2005-04-13 09:17:19 UTC (rev 7359)
+++ trunk/gnue-appserver/src/data.py    2005-04-13 14:00:02 UTC (rev 7360)
@@ -912,13 +912,15 @@
     Add constraints for a given table. 
 
     @param table: name of the table to add constraints for
-    @param constraints: sequence of master-tables for the given table
+    @param constraints: dictionary of master-tables for the given table
     """
 
-    if len (constraints):
+    if constraints:
       cdict = self.__constraints.setdefault (table.lower (), {})
-      for item in constraints:
-        cdict [item.lower ()] = True
+      for (reftable, refitems) in constraints.items ():
+        elements = cdict.setdefault (reftable.lower (), {})
+        for item in refitems:
+          elements [item] = True
 
 
   # ---------------------------------------------------------------------------
@@ -1026,6 +1028,7 @@
 
     tables = {}
     data   = {}
+    fishes = {}
 
     gDebug (1, "Constraints: %s" % self.__constraints)
     gDebug (1, "Unordered  : %s" % records)
@@ -1046,8 +1049,11 @@
     for (table, deps) in tables.items ():
       if self.__constraints.has_key (table):
         for constraint in self.__constraints [table]:
-          if constraint != table and tables.has_key (constraint):
-            deps.append (constraint)
+          if tables.has_key (constraint):
+            if constraint != table:
+              deps.append (constraint)
+            else:
+              fishes [table] = self.__constraints [table] [table]
 
     # Now create an ordered sequence taking care of dependencies
     order = []
@@ -1077,13 +1083,88 @@
 
     # And finally flatten everything to a sequence of tuples
     result = []
+    extend = result.extend
+
     for table in order:
-      result.extend (data [table])
+      if table in fishes:
+        extend (self.__fishSort (table, data [table], fishes [table]))
+      else:
+        extend (data [table])
 
     return result
 
 
   # ---------------------------------------------------------------------------
+  # Create an order within a table so it does not violate fish-hook constraints
+  # ---------------------------------------------------------------------------
+
+  def __fishSort (self, table, rows, constraints):
+    """
+    Sort all given rows of a table to not violate the given constraints.
+
+    @param table: name of the table
+    @param rows: sequence of tuples (table, rowid)
+    @param constraints: dictionary with all constraints per row
+
+    @result: ordered sequence of tuples (table, rowid)
+
+    @raises CircularReferenceError: if the given data contains reference cycles
+    """
+
+    # First create a dependency tree for all rows, holding a sequence of those
+    # rowids which must be processed before the current row
+    dTree = {}
+    for (t, row) in rows:
+      deps = dTree.setdefault (row, [])
+
+      r = record (self.__cache, self.__connections, self.__database, table, 
row)
+      for depField in constraints:
+        value = r.getField (depField)
+        if value and value not in deps:
+          deps.append (value)
+
+    # After we have created a complete dependency tree, we need to remove all
+    # those rows from the master-sequences, which do not have a key in the tree
+    # itself. Usually these are rows not contained in the current operation
+    # (insertion/deletion) so we can assume that they do exist. Otherwise it
+    # would not be possible to set a reference in a newly inserted record to an
+    # existing record.
+    for deps in dTree.values ():
+      for row in deps [:]:
+        if not row in dTree:
+          deps.remove (row)
+
+    # Now create an ordered sequence taking care of dependencies
+    order = []
+
+    while dTree:
+      addition = []
+
+      for (detail, masters) in dTree.items ():
+        # If a row has no masters, add it to the result
+        if not len (masters):
+          addition.append (detail)
+
+          # and remove that row from all dependency sequence it occurs
+          for ref in dTree.values ():
+            if detail in ref:
+              ref.remove (detail)
+
+          # finally remove it from the dictionary
+          del dTree [detail]
+
+      # If no row without a dependency was found, but there are still
+      # entries in the dependency tree, they *must* have circular references
+      if not len (addition) and len (dTree):
+        raise CircularReferenceError
+
+      order.extend (addition)
+
+    return zip ([table] * len (order), order)
+
+
+
+  # ---------------------------------------------------------------------------
   # Undo all changes
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-appserver/src/geasInstance.py
===================================================================
--- trunk/gnue-appserver/src/geasInstance.py    2005-04-13 09:17:19 UTC (rev 
7359)
+++ trunk/gnue-appserver/src/geasInstance.py    2005-04-13 14:00:02 UTC (rev 
7360)
@@ -103,7 +103,7 @@
     self.__record     = record
     self.__classdef   = classdef
 
-    self.__connection.setConstraints (classdef.table, classdef.masters.keys ())
+    self.__connection.setConstraints (classdef.table, classdef.masters)
 
 
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-appserver/src/geasRpcServer.py
===================================================================
--- trunk/gnue-appserver/src/geasRpcServer.py   2005-04-13 09:17:19 UTC (rev 
7359)
+++ trunk/gnue-appserver/src/geasRpcServer.py   2005-04-13 14:00:02 UTC (rev 
7360)
@@ -40,7 +40,7 @@
 from gnue.appserver import geasConfiguration
 
 
-_GC_DEBUG = False   # Set this to True to activate garbage collection debugging
+_GC_DEBUG = True    # Set this to True to activate garbage collection debugging
 
 # =============================================================================
 # RPC application class

Modified: trunk/gnue-appserver/src/repository.py
===================================================================
--- trunk/gnue-appserver/src/repository.py      2005-04-13 09:17:19 UTC (rev 
7359)
+++ trunk/gnue-appserver/src/repository.py      2005-04-13 14:00:02 UTC (rev 
7360)
@@ -546,14 +546,15 @@
   # Add a given class as master of the class
   # ---------------------------------------------------------------------------
 
-  def addMasterClass (self, aMaster):
+  def addMasterClass (self, aProperty, aMaster):
     """
-    This function adds a given class to the dictionary of master-classes.
+    Add a given class to the dictionary of master-classes.
 
+    @param aProperty: name of the property holding the pointer to master-class
     @param aMaster: class wrapper instance to be added
     """
 
-    self.masters [aMaster.fullName] = aMaster
+    self.masters.setdefault (aMaster.fullName, []).append (aProperty)
 
 
   # ---------------------------------------------------------------------------
@@ -667,7 +668,7 @@
     # If the property is a reference to another class, the referenced class
     # is a master of this class
     if r is not None:
-      classes [self.gnue_class].addMasterClass (r)
+      classes [self.gnue_class].addMasterClass (self.fullName, r)
 
 
 

Modified: trunk/gnue-appserver/tests/data.py
===================================================================
--- trunk/gnue-appserver/tests/data.py  2005-04-13 09:17:19 UTC (rev 7359)
+++ trunk/gnue-appserver/tests/data.py  2005-04-13 14:00:02 UTC (rev 7360)
@@ -486,6 +486,10 @@
     spocksId = orgCrew [-1].getField (u'gnue_id')
     self.connection.deleteRecord (u'address_person', spocksId)
 
+    # And the captain becomes the senior of Checkov
+    orgCrew [-2].putField (u'address_senior',
+                           u'00000000000000000000000000001100')
+
     # And a new crew member signs on
     new = self.connection.insertRecord (u'address_person')
     new.initialized ()
@@ -553,6 +557,10 @@
                 (u'Pavel Andreievich Chekov', u'RU')]
     self.assertEqual (expected, secData)
 
+    self.connection.setConstraints (u'address_person',
+        {u'address_country': {u'address_country': True},
+         u'address_person':  {u'address_senior': True}})
+
     self.remove = [(u'address_person', new.getField (u'gnue_id')),
                    (u'address_country', oz.getField (u'gnue_id'))]
 
@@ -582,14 +590,20 @@
     spock.putField (u'address_meettime', u'6:30')
     spock.putField (u'address_lastmeeting', u'2270-05-17 08:00')
     spock.putField (u'address_human', False)
+    spock.putField (u'address_senior', u'00000000000000000000000000001100')
     # This is a bit hackish cause we're changing the primary key
-    spock.putField (u'gnue_id', '00000000000000000000000000001101')
+    spock.putField (u'gnue_id', u'00000000000000000000000000001101')
 
     # Reset the country for McCoy to the US
     mccoy = self.connection.findRecord (u'address_person',
                      u'00000000000000000000000000001102', [u'address_country'])
     mccoy.putField (u'address_country', u'000000000000000000000020000000E3')
 
+    # Reassign Spock as Checkov's senior
+    checkov = self.connection.findRecord (u'address_person',
+          u'00000000000000000000000000001103', [u'address_senior'])
+    checkov.putField (u'address_senior', u'00000000000000000000000000001101')
+
     # And remove newly added records
     for (table, row) in self.remove:
       self.connection.deleteRecord (table, row)





reply via email to

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