commit-gnue
[Top][All Lists]
Advanced

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

[gnue] r7233 - trunk/gnue-appserver/src


From: johannes
Subject: [gnue] r7233 - trunk/gnue-appserver/src
Date: Sun, 20 Mar 2005 08:08:14 -0600 (CST)

Author: johannes
Date: 2005-03-20 08:08:13 -0600 (Sun, 20 Mar 2005)
New Revision: 7233

Modified:
   trunk/gnue-appserver/src/data.py
   trunk/gnue-appserver/src/geasInstance.py
Log:
commit () takes care of constraints automatically


Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py    2005-03-20 12:35:44 UTC (rev 7232)
+++ trunk/gnue-appserver/src/data.py    2005-03-20 14:08:13 UTC (rev 7233)
@@ -600,6 +600,7 @@
     self.__confirmedCache   = None
     self.__confirmedInserts = []
     self.__confirmedDeletes = []
+    self.__constraints = {}
 
     self.__uuidType = gConfig ('uuidtype').lower ()
 
@@ -666,18 +667,7 @@
     return recordset (self.__cache, self.__connections, self.__database,
                       content, _conditionTree (conditions), order)
 
-  # ---------------------------------------------------------------------------
-  # Generate a new object id
-  # ---------------------------------------------------------------------------
 
-  def __generateId (self):
-
-    if self.__uuidType == 'time':
-      return UUID.generateTimeBased ()
-    else:
-      return UUID.generateRandom ()
-
-
   # ---------------------------------------------------------------------------
   # Create a new record
   # ---------------------------------------------------------------------------
@@ -690,7 +680,11 @@
     """
     checktype (table, UnicodeType)
 
-    id = self.__generateId ()
+    if self.__uuidType == 'time':
+      id = UUID.generateTimeBased ()
+    else:
+      id = UUID.generateRandom ()
+
     r = record (self.__cache, self.__connections, self.__database, table, id)
     self.__cache.write (table, id, u'gnue_id', None, 0)  # old id is None
     self.__cache.write (table, id, u'gnue_id', id, 1)    # new id
@@ -769,6 +763,24 @@
 
 
   # ---------------------------------------------------------------------------
+  # Add constraints for a table
+  # ---------------------------------------------------------------------------
+
+  def setConstraints (self, table, constraints):
+    """
+    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
+    """
+
+    if len (constraints):
+      cdict = self.__constraints.setdefault (table.lower (), {})
+      for item in constraints:
+        cdict [item.lower ()] = True
+
+
+  # ---------------------------------------------------------------------------
   # Write all changes back to the database
   # ---------------------------------------------------------------------------
 
@@ -784,10 +796,10 @@
     recNo   = 0
 
     # first perform all inserts
-    for (table, row) in self.__inserted [:]:
-      recNo += 1
-      if self.__cache.status (table, row) == 'inserted':
+    if self.__inserted:
+      for (table, row) in self.__orderInserts ():
         fields = tables [table] [row]
+        recNo += 1
 
         backend.insert (table, fields, recNo)
         self.__inserted.remove ((table, row))
@@ -797,6 +809,7 @@
 
         self.__cache.makeClean (table, row)
 
+
     # second perform all updates
     for (table, rows) in tables.items ():
       for (row, fields) in rows.items ():
@@ -808,10 +821,11 @@
           self.__cache.makeClean (table, row)
 
     # perform all deletes
-    for (table, row) in self.__deleted:
-      recNo += 1
-      backend.delete (table, {'gnue_id': row}, recNo)
-      self.__cache.remove (table, row)
+    if len (self.__deleted):
+      for (table, row) in self.__orderDeletes ():
+        recNo += 1
+        backend.delete (table, {'gnue_id': row}, recNo)
+        self.__cache.remove (table, row)
 
 
     self.__deleted = []
@@ -829,6 +843,108 @@
 
 
   # ---------------------------------------------------------------------------
+  # Create an ordered sequence of new records
+  # ---------------------------------------------------------------------------
+
+  def __orderInserts (self):
+    """
+    Order all records scheduled for insertion, so constraint violations are
+    avoided.
+
+    @return: sequence of (table, row) tuples in a sane order for insertion
+    """
+
+    records = [(table, row) for (table, row) in self.__inserted \
+                             if self.__cache.status (table, row) == 'inserted']
+    return self.__orderByDependency (records)
+
+
+  # ---------------------------------------------------------------------------
+  # Order all records scheduled for deletion
+  # ---------------------------------------------------------------------------
+
+  def __orderDeletes (self):
+    """
+    Order all records scheduled for deletion, so constraint violations are
+    avoided.
+
+    @return: sequence of (table, row) tuples in a sane order for deletion
+    """
+
+    order = self.__orderByDependency (self.__deleted)
+    # since we do deletes we need a reversed order
+    order.reverse ()
+
+    return order
+
+
+  # ---------------------------------------------------------------------------
+  # Order a sequence of (table, row) tuples by their dependencies
+  # ---------------------------------------------------------------------------
+
+  def __orderByDependency (self, records):
+    """
+    Order a sequence of records (table, row) so their dependencies given by
+    setConstraints () are fullfilled. The result starts with elements having no
+    dependency at all.
+
+    @param records: sequence with (table, row) tuples
+    @return: ordered sequence with (table, row) tuples
+    """
+
+    tables = {}
+    data   = {}
+
+    # First create a dictionary with all tables scheduled for processing
+    for (table, row) in records:
+
+      tables [table] = []
+      rows = data.setdefault (table, [])
+      rows.append ((table, row))
+
+    # Now, add all those constraints which are also scheduled for insertion.
+    # This eliminates constraints which are currently NULL.
+    for (table, deps) in tables.items ():
+      if self.__constraints.has_key (table):
+        for constraint in self.__constraints [table].keys ():
+          if tables.has_key (constraint):
+            deps.append (constraint)
+
+    # Now create an ordered sequence taking care of dependencies
+    order = []
+
+    while tables:
+      addition = []
+
+      for (table, deps) in tables.items ():
+        # If a table has no dependencies, add it to the result
+        if not len (deps):
+          addition.append (table)
+
+          # and remove that table from all other tables dependency sequence
+          for ref in tables.values ():
+            if table in ref:
+              ref.remove (table)
+
+          # finally remove it from the dictionary
+          del tables [table]
+
+      # If no tables without a dependency was found, but there are still
+      # entries in the tables dictionary, they *must* have circular references
+      if not len (addition) and len (tables):
+        raise CircularReferencesError
+
+      order.extend (addition)
+
+    # And finally flatten everything to a sequence of tuples
+    result = []
+    for table in order:
+      result.extend (data [table])
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
   # Undo all changes
   # ---------------------------------------------------------------------------
 

Modified: trunk/gnue-appserver/src/geasInstance.py
===================================================================
--- trunk/gnue-appserver/src/geasInstance.py    2005-03-20 12:35:44 UTC (rev 
7232)
+++ trunk/gnue-appserver/src/geasInstance.py    2005-03-20 14:08:13 UTC (rev 
7233)
@@ -103,6 +103,9 @@
     self.__record     = record
     self.__classdef   = classdef
 
+    self.__connection.setConstraints (classdef.table, classdef.masters.keys ())
+
+
   # ---------------------------------------------------------------------------
   # Convert a value into the given type if possible
   # ---------------------------------------------------------------------------





reply via email to

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