commit-gnue
[Top][All Lists]
Advanced

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

[gnue] r6901 - in trunk/gnue-appserver/src: . language


From: johannes
Subject: [gnue] r6901 - in trunk/gnue-appserver/src: . language
Date: Fri, 14 Jan 2005 02:34:51 -0600 (CST)

Author: johannes
Date: 2005-01-14 02:34:49 -0600 (Fri, 14 Jan 2005)
New Revision: 6901

Modified:
   trunk/gnue-appserver/src/data.py
   trunk/gnue-appserver/src/geasFilter.py
   trunk/gnue-appserver/src/geasSession.py
   trunk/gnue-appserver/src/language/Object.py
Log:
Indirect properties are linked in using "LEFT OUTER JOINS", access to indirect 
properties with intermediate 'NULL' values is possible (like foo.bar.baz) 
without an exception


Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py    2005-01-14 03:23:01 UTC (rev 6900)
+++ trunk/gnue-appserver/src/data.py    2005-01-14 08:34:49 UTC (rev 6901)
@@ -444,31 +444,36 @@
 def _createDatasource (connections, database, content, order = None):
 
   # build table list, field list, and join condition
+  master = []
   tables = []
   fields = []
   conditions = None
   for (alias, (table, fk_alias, fk_field, fieldlist)) in content.items ():
     if alias:
-      tables.append (table + ' ' + alias)
+      if not fk_alias:
+        master.append ((None, table + ' ' + alias))
       fields.extend ([alias + '.' + field for field in fieldlist])
     else:
-      tables.append (table)
+      master.append ((None, table))
       fields.extend (fieldlist)
+
     if fk_alias:
-      # FIXME: Instead of a condition we better create a 'LEFT JOIN' later
-      c = GConditions.buildTreeFromList (
-          ['eq', ['field', alias + u'.gnue_id'],
-                 ['field', fk_alias + u'.' + fk_field]])
-      if conditions:
-        conditions = GConditions.combineConditions (conditions, c)
-      else:
-        conditions = c
+      table = u"LEFT JOIN %s %s ON %s.gnue_id = %s.%s" % \
+          (table, alias, alias, fk_alias, fk_field)
+      tables.append ((alias, table))
 
+  # After building up the table sequences we need to make sure they're sorted
+  # by their alias, otherwise the left outer joins won't work.
+  master.sort ()
+  tables.sort ()
+
   # prepare attributes of the datasource
   attributes = {}
   attributes ['name']      = ''
   attributes ['database']  = database
-  attributes ['table']     = string.join (tables, ', ')
+  attributes ['table']     = "%s %s" % \
+      (string.join ([m [1] for m in master], ','),
+       string.join ([t [1] for t in tables], ' '))
   attributes ['primarykey'] = 'gnue_id'
 
   # give the backend a hint that it's working for appserver :)
@@ -936,23 +941,31 @@
       else:
         id = self.__resultSet.current [u'gnue_id']
 
-      # build the record object
-      r = record (self.__cache, self.__connections, self.__database, table, id)
-      r._fill (alias, fields, self.__resultSet.current)
-      records [alias] = r
+      if id:
+        # build the record object
+        r = record (self.__cache, self.__connections, self.__database,
+                    table, id)
+        r._fill (alias, fields, self.__resultSet.current)
+        records [alias] = r
 
-      # the table having no join condition is the "main" table
-      if not fk_alias:
-        result = r
+        # the table having no join condition is the "main" table
+        if not fk_alias:
+          result = r
 
     # iterate again to put the foreign keys in the cache
     for (alias, (table, fk_alias, fk_field, fields)) in self.__content.items():
       if fk_alias:
-        (records [fk_alias])._cache (fk_field,
-                                     (records [alias]).getField (u'gnue_id'))
+        if records.has_key (alias):
+          value = records [alias].getField (u'gnue_id')
+        else:
+          value = None
 
+        if records.has_key (fk_alias):
+          records [fk_alias]._cache (fk_field, value)
+
     return result
 
+
   # ---------------------------------------------------------------------------
   # Return the first record
   # ---------------------------------------------------------------------------

Modified: trunk/gnue-appserver/src/geasFilter.py
===================================================================
--- trunk/gnue-appserver/src/geasFilter.py      2005-01-14 03:23:01 UTC (rev 
6900)
+++ trunk/gnue-appserver/src/geasFilter.py      2005-01-14 08:34:49 UTC (rev 
6901)
@@ -89,7 +89,7 @@
       fields.sort ()
 
       classdef = self.__sm.classes.find (fId)
-      master   = classdef.gnue_filter
+      master   = classdef.gnue_filter and classdef.gnue_filter or None
       if master is not None:
         master = self.__sm.classes.find (master.gnue_id).fullName
 
@@ -127,7 +127,7 @@
 
     # First get all filters defined in class repository
     for klass in self.__sm.classes.values ():
-      if klass.gnue_filter is not None:
+      if klass.gnue_filter:
         self.__addFilter (klass.gnue_filter)
 
     result = []
@@ -156,7 +156,7 @@
     if not self.__fDict.has_key (filterId):
       self.__fDict [filterId] = []
 
-    if filterClass.gnue_filter is not None:
+    if filterClass.gnue_filter:
       refId = filterClass.gnue_filter.gnue_id
       if not refId in self.__fDict [filterId]:
         self.__fDict [filterId].append (refId)

Modified: trunk/gnue-appserver/src/geasSession.py
===================================================================
--- trunk/gnue-appserver/src/geasSession.py     2005-01-14 03:23:01 UTC (rev 
6900)
+++ trunk/gnue-appserver/src/geasSession.py     2005-01-14 08:34:49 UTC (rev 
6901)
@@ -469,7 +469,7 @@
 
     instance = geasInstance.geasInstance (self, self.__connection, record,
                                           classdef)
-    if classdef.gnue_filter is not None:
+    if classdef.gnue_filter:
       fId   = classdef.gnue_filter.gnue_id
       fName = self.sm.classes.find (fId).fullName
       instance.put ([fName], [self.__filterValue (fId)])
@@ -667,7 +667,7 @@
     else:
       raise ConditionDataTypeError, condition
   
-    if classdef.gnue_filter is not None:
+    if classdef.gnue_filter:
       useFilter  = True
       filterName = self.sm.classes.find (classdef.gnue_filter.gnue_id).fullName
       cList = cTree.findChildrenOfType ('GCCField', allowAllChildren = True)
@@ -726,7 +726,7 @@
 
   def __filterCondition (self, classdef):
 
-    if classdef.gnue_filter is not None:
+    if classdef.gnue_filter:
       filterId   = classdef.gnue_filter.gnue_id
       filterName = self.sm.classes.find (filterId).fullName
       filterCond = GConditions.buildConditionFromDict ( \

Modified: trunk/gnue-appserver/src/language/Object.py
===================================================================
--- trunk/gnue-appserver/src/language/Object.py 2005-01-14 03:23:01 UTC (rev 
6900)
+++ trunk/gnue-appserver/src/language/Object.py 2005-01-14 08:34:49 UTC (rev 
6901)
@@ -92,6 +92,13 @@
       # Convert reference fields to object references
       if '_' in datatype and value is not None:
         return Object (self.__session, datatype, value)
+
+      elif value is None:
+        if '_' in datatype:
+          return NullObject ()
+        else:
+          return None
+
       else:
         return value
 
@@ -177,3 +184,111 @@
     self.__session.getSessionManager ().delete (
                self.__session.getSessionId (), self.__class, [self.objectId])
     self.objectId = None
+
+
+# =============================================================================
+# Class implementing None values for reference-properties
+# =============================================================================
+
+class NullObject:
+
+  # ---------------------------------------------------------------------------
+  # Property access method
+  # ---------------------------------------------------------------------------
+
+  def __getattr__ (self, attr):
+    """
+    This function simulates access to a property of the instance by returning
+    itself, so a following, property access will still work.
+
+    @return: self
+    """
+    return self
+
+
+  # ---------------------------------------------------------------------------
+  # Truth-test
+  # ---------------------------------------------------------------------------
+
+  def __nonzero__ (self):
+    """
+    A NullObject instance always has a truth-value of 'False' (like None has).
+    This is used for constructs like: "if x: ..."
+    """
+    return False
+
+
+  # ---------------------------------------------------------------------------
+  # Rich comparison
+  # ---------------------------------------------------------------------------
+
+  def __cmp__ (self, other):
+    """
+    An instance of NullObject is True if, and only if, the object compared with
+    is None. This comparison is usually used for sorting.
+    """
+
+    return cmp (None, other)
+
+  # ---------------------------------------------------------------------------
+  # Comparison: equality
+  # ---------------------------------------------------------------------------
+
+  def __eq__ (self, other):
+    """
+    An instance of NullObject is equal only to None
+    """
+
+    return other is None
+
+
+  # ---------------------------------------------------------------------------
+  # Comparison: inequality
+  # ---------------------------------------------------------------------------
+
+  def __ne__ (self, other):
+    """
+    An instance of NullObject is equal only to None
+    """
+
+    return other is not None
+
+
+  # ---------------------------------------------------------------------------
+  # Official string representation
+  # ---------------------------------------------------------------------------
+
+  def __repr__ (self):
+    """
+    This function returns the official string representation of an instance
+    """
+
+    return "<NullObject at %s>" % hex (id (self))
+
+
+  # ---------------------------------------------------------------------------
+  # Informal string represenation
+  # ---------------------------------------------------------------------------
+
+  def __str__ (self):
+    """
+    The informal representation is just 'empty'
+    """
+    return ''
+
+
+# =============================================================================
+# Small unit test
+# =============================================================================
+
+if __name__ == '__main__':
+  x = NullObject ()
+  print x is None
+  print x == None
+  if x:
+    print "ok"
+  else:
+    print "nope"
+
+  print "x.y=", x.y
+  print "x.a.b.c=", x.a.b.c, repr (x.a.b.c)





reply via email to

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