[Zope3-checkins] CVS: zopeproducts/pypgsqlda - adapter.py:1.6

Christian 'Tiran' Heimes heimes@faho.rwth-aachen.de
Wed, 19 Mar 2003 17:18:51 -0500


Update of /cvs-repository/zopeproducts/pypgsqlda
In directory cvs.zope.org:/tmp/cvs-serv30925/zopeproducts/pypgsqlda

Modified Files:
	adapter.py 
Log Message:
modified converter_mapping after some testing
added converter for geometric types, inet and smallint

=== zopeproducts/pypgsqlda/adapter.py 1.5 => 1.6 ===
--- zopeproducts/pypgsqlda/adapter.py:1.5	Tue Mar 18 15:23:35 2003
+++ zopeproducts/pypgsqlda/adapter.py	Wed Mar 19 17:18:50 2003
@@ -20,6 +20,8 @@
 
 from zope.app.rdb import ZopeDatabaseAdapter, parseDSN, identity
 
+import string
+
 class pypgsqlAdapter(ZopeDatabaseAdapter):
     """A pypgsql adapter for Zope3"""
 
@@ -49,8 +51,31 @@
         else:
             return identity
 
+# helpers
+
+def isPgArray(data):
+    """Check if data is a postgres array"""   
+    return isinstance(data, PgArray)
+
 # Converters
 
+def convertINet(data):
+    """Converts inet and cidr to an nested tuple
+    
+    Return a nested tuple of the form (hostaddress, netmask) where
+    hostaddress itself is a tuple of ints and netmask is an int.
+    
+    FYI: cidr and inet can handle only ipv4 (12 bytes)
+    
+    XXX: make this a special type
+    """
+    addr = unicode(data).split('/')
+    if len(addr) == 2:
+        addr[1] = string.atoi(addr[1])
+    else:
+        addr.append(32)
+    return (tuple([string.atoi(a) for a in addr[0].split('.')]), addr[1])
+
 def convertInterval(data):
     """Returns the length of the interval in seconds."""
     return data.seconds
@@ -58,65 +83,157 @@
 def convertBool(data):
     """Returns a boolean as normal python boolean."""
     return not not data
+
+def convertSmallInt(data):
+    """Converts a string containing a small int (int2) to int"""
+    return string.atoi(unicode(data))    
+
+
+class GeometricError(Exception): pass
+
+import re
+# matching an open path e.g. [(0,0),(1,1)]
+isOpenPath = re.compile(r"^\[\(.*\)\]$")
+
+# matching a closed path e.g. ((0,0),(1,1))
+isClosedPath = re.compile(r"^\(\(.*\)\)$")
+
+# group a circle e.g. <(1,1),0.5> into (1.0,1.0) as the middle point
+# and 0.5 as the radius
+groupCircle = re.compile(r"^<(\([\d.]+,[\d.]+\)),([\d.]+)>$")
+
+# group a single point e.g. (0,1) into 0 as the x value and 1 as the y value
+groupPoint = re.compile(r"^\(([\d.]+),([\d.]+)\)$")
+
+# group a path or a box e.g.((0,0),(1,1)) or [(0,0),(1,1)] into a 
+# list of points
+groupPointList = re.compile(r"(\([\d.]+,[\d.]+\))")
+
+def convertPoint(data):
+    """Returns tuple (x,y) coordinate of floats
     
-def convertMac(data):
-    """Return a Mac as a normal string."""
-    return unicode(data) 
-        
-def convertNet(data):
-    """Return a network address as tuple (network, mask)."""
-    return unicode(data).split('/')
+    XXX: make this a special type
+    """
+    point = groupPoint.match(unicode(data)).groups()
+    if len(point) != 2:
+        raise GeometricError, u"'%s' has wrong size" % data
+    return tuple([string.atof(p) for p in point])
+
+def convertBox(data):
+    """Returns nested list upper right and lower left point
+    
+    XXX: make this a special type
+    """
+    box = groupPointList.findall(unicode(data))
+    if len(box) != 2:
+        raise GeometricError, u"'%s' has wrong size" % data
+    return tuple([convertPoint(p) for p in box])
+
+def convertCircle(data):
+    """Returns tuple ((x,y), radius) of floats
+    
+    XXX: make this a special type
+    """
+    circle = groupCircle.match(unicode(data)).groups()
+    if len(circle) != 2:
+        raise GeometricError, u"'%s' has wrong size" % data
+    return (convertPoint(circle[0]), string.atof(circle[1]))
+
+def convertLine(data):
+    """Returns tuple of two points, which defines the infinite line
+    
+    XXX: make this a special type
+    """
+    line = groupPointList.findall(unicode(data))
+    if len(line) != 2:
+        raise GeometricError, u"'%s' has wrong size" % data
+    return tuple([convertPoint(p) for p in line])
+
+def convertLSeg(data):
+    """Returns list of two points
+    
+    XXX: make this a special type
+    """
+    lseg = groupPointList.findall(unicode(data))
+    if len(lseg) != 2:
+        raise GeometricError, u"'%s' has wrong size" % data
+    return [convertPoint(p) for p in lseg]
+
+def convertPath(data):
+    """Returns list or tuple of n points, tuple is used for a closed path
+    
+    XXX: make this a special type
+    """
+    if isOpenPath.match(unicode(data)):
+        return [convertPoint(p)
+            for p in groupPointList.findall(unicode(data))]
+    elif isClosedPath.match(unicode(data)):
+        return tuple([convertPoint(p)
+            for p in groupPointList.findall(unicode(data))])
+    else:
+        raise GeometricError, u"'%s' has wrong format" % data
+
+def convertPolygon(data):
+    """Returns tuple of n points
+    
+    XXX: make this a special type
+    """
+    return tuple([convertPoint(p) for p in groupPointList.findall(unicode(data))]) 
     
-def debug(data):    
+def debug(data):
+    """XXX  used for debugging"""
     import pdb;
     pdb.set_trace()
     print data
 
-# types from pypgsql/libpqmodule.c        
+# types from pypgsql/libpqmodule.c
 converter_mapping = {
-        'abstime' : debug,       # PG_ABSTIME           time 
-        'aclitem' : debug,       # PG_ACLITEM           unicode (sys)
-        'blob' : debug,          # PG_BLOB              string
-        'bool' : convertBool,          # PG_BOOL        boolean
-        'box' : debug,           # PG_BOX               geometric.box
-        'char' : debug,          # PG_BPCHAR            identity
-        'bytea' : debug,         # PG_BYTEA             string
-        'money' : debug,         # PG_CASH              float
-        'cid' : debug,           # PG_CID               unicode (sys)
-        'cidr' : debug,          # PG_CIDR              unicode
-        'circle' : debug,        # PG_CIRCLE            geometric.circle
-        'date' : debug,          # PG_DATE              datetime.date
-        'float4' : debug,        # PG_FLOAT4            float
-        'float' : debug,         # PG_FLOAT8            float
-        'inet' : debug,          # PG_INET              unicode 
-        'int2' : debug,          # PG_INT2              integer
-        'int2vector' : debug,    # PG_INT2VECTOR        unicode (sys)
-        'integer' : debug,       # PG_INT4              integer
-        'bigint' : debug,        # PG_INT8              longint
-        'interval' : convertInterval,   # PG_INTERVAL   datetime.delta
-        'line' : debug,          # PG_LINE              geometric.line
-        'lseg' : debug,          # PG_LSEG              geometric.linesegment
-        'macaddr' : debug,       # PG_MACADDR           unicode
-        'name' : debug,          # PG_NAME              unicode
-        'numeric' : debug,       # PG_NUMERIC           float
-        'oid' : debug,           # PG_OID               unicode (sys)
-        'oidvector' : debug,     # PG_OIDVECTOR         unicode (sys)
-        'path' : debug,          # PG_PATH              geometric.path
-        'point' : debug,         # PG_POINT             geometric.point
-        'polygon' : debug,       # PG_POLYGON           geometric.polygon
-        'refcursor' : debug,     # PG_REFCURSOR         unicode (sys)
-        'regproc' : debug,       # PG_REGPROC           unicode (sys)
-        'reltime' : debug,       # PG_RELTIME           datetime.delta
-        'rowid' : debug,         # PG_ROWID             longint 
-        'text' : debug,          # PG_TEXT              unicode 
-        'tid' : debug,           # PG_TID               unicode (sys)
-        'time' : debug,          # PG_TIME              datetime.time
-        'timestamp' : debug,     # PG_TIMESTAMP         datetime.datetime
-        'timestamptz' : debug,   # PG_TIMESTAMPTZ       datetime.datetime
-        'tinterval' : debug,     # PG_TINTERVAL         datetime.delta
-        'unknown' : debug,       # PG_UNKNOWN           unicode (sys)
-        'varbit' : debug,        # PG_VARBIT            XXX
-        'varchar' : debug,       # PG_VARCHAR           unicode
-        'xid' : debug,           # PG_XID               unicode (sys)
-        'zpbit' : debug          # PG_ZPBIT             identity XXX debug this 
+    'abstime'   : debug,            # PG_ABSTIME        time 
+    'aclitem'   : unicode,          # PG_ACLITEM    S   unicode XXX PgArray
+    'blob'      : string,           # PG_BLOB           string
+    'bool'      : convertBool,      # PG_BOOL           boolean
+    'box'       : convertBox,       # PG_BOX            geometric.box
+    'char'      : identity,         # PG_BPCHAR         identity XXX ??
+    'bytea'     : string,           # PG_BYTEA          string
+    'money'     : float,            # PG_CASH           float XXX: special?
+    'cid'       : debug,            # PG_CID        S   unicode XXX number?
+                                    # need more information! could be connection id
+    'cidr'      : convertINet,      # PG_CIDR           network XXX
+    'circle'    : convertCircle,    # PG_CIRCLE         geometric.circle
+    'date'      : debug,            # PG_DATE           datetime.date
+    'float4'    : identity,         # PG_FLOAT4         float
+    'float'     : identity,         # PG_FLOAT8         float
+    'inet'      : convertINet,      # PG_INET           network XXX 
+    'int2'      : convertSmallInt,  # PG_INT2           integer
+    'int2vector' : unicode,         # PG_INT2VECTOR S   unicode XXX PgArray of int2
+    'integer'   : identity,         # PG_INT4           integer
+    'bigint'    : long,             # PG_INT8           longint
+    'interval'  : convertInterval,  # PG_INTERVAL       datetime.delta
+    'line'      : convertLine,      # PG_LINE           geometric.line (XXX not implemented in pgsql 7.2)
+    'lseg'      : convertLSeg,      # PG_LSEG           geometric.linesegment
+    'macaddr'   : unicode,          # PG_MACADDR        unicode
+    'name'      : identity,         # PG_NAME       S   identity == unicode
+    'numeric'   : float,            # PG_NUMERIC        float XXX: special?
+    'oid'       : debug,            # PG_OID        S   unicode XXX: what? is NOT oid in pgpPgAdmin, see rowid
+    'oidvector' : unicode,          # PG_OIDVECTOR  S   unicode XXX: PgArray
+    'path'      : convertPath,      # PG_PATH           geometric.path
+    'point'     : convertPoint,     # PG_POINT          geometric.point
+    'polygon'   : convertPolygon,   # PG_POLYGON        geometric.polygon
+    'refcursor' : unicode,          # PG_REFCURSOR  S   unicode XXX: what? identitiy?
+    'regproc'   : unicode,          # PG_REGPROC    S   unicode XXX: what? identitiy?
+    'reltime'   : debug,            # PG_RELTIME        datetime.delta
+    'rowid'     : long,             # PG_ROWID      S   longint; rowid is oid in pgpPgAdmin
+    'text'      : identity,         # PG_TEXT           unicode 
+    'tid'       : debug,            # PG_TID        S   unicode XXX number? what?
+                                    # need more information, could be transaction id
+    'time'      : debug,            # PG_TIME           datetime.time
+    'timestamp' : debug,            # PG_TIMESTAMP      datetime.datetime
+    'timestamptz' : debug,          # PG_TIMESTAMPTZ    datetime.datetime
+    'tinterval' : debug,            # PG_TINTERVAL      datetime.delta
+    'unknown'   : unicode,          # PG_UNKNOWN    S?  unicode (unknown), XXX what?
+    'varbit'    : unicode,          # PG_VARBIT         XXX see zpbit!
+    'varchar'   : identity,         # PG_VARCHAR        unicode
+    'xid'       : long,             # PG_XID        S   xid is a longint [was: unicode]
+    'zpbit'     : unicode           # PG_ZPBIT          unicode  XXX: pgsql returns string
+                                    # make int?, this would kill all leading zeros!
     }