changeset 3:d70e57193731

new executeZSQL method that returns Zope Results. new ZDBInterfaceFolder that doesn't do much yet.
author casties
date Mon, 14 Feb 2011 23:20:43 +0100
parents 881fcea6a57d
children 0ade331198de
files DBInterface.py RestDbInterface.py ZDBInterfaceFolder.py __init__.py zpt/addZDBInterfaceFolder.zpt zpt/editRestDbInterface.zpt zpt/editZDBInterfaceFolder.zpt
diffstat 7 files changed, 166 insertions(+), 133 deletions(-) [+]
line wrap: on
line diff
--- a/DBInterface.py	Mon Feb 14 11:11:34 2011 +0100
+++ b/DBInterface.py	Mon Feb 14 23:20:43 2011 +0100
@@ -12,6 +12,7 @@
 psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
 
 from Products.ZSQLMethods.SQL import SQLConnectionIDs
+from Shared.DC.ZRDB.Results import Results
 
 
 def unicodify(s,alternate='latin-1'):
@@ -65,46 +66,80 @@
     return s
 
 
-class DbInterface:
-    """Object for database queries
-    """
-    def __init__(self, id, title, connection_id=None):
+class DBInterface:
+    """Object for database queries"""
+    
+    def __init__(self, connection_id=None):
         """init"""
-        self.id = id
-        self.title = title
         # database connection id
         self.connection_id = connection_id        
 
+    def getConnectionIDs(self):
+        """return list of available connection ids"""
+        return SQLConnectionIDs(self)
+
+    def getDB(self):
+        """returns DB object"""
+        # TODO: can we cache and reuse a DB object?
+        if self.connection_id is None:
+            # try to take the first existing ID
+            connids = self.getConnectionIDs()
+            if len(connids) > 0:
+                connection_id = connids[0][1]
+                self.connection_id = connection_id
+                logging.debug("connection_id: %s"%repr(connection_id))
+
+        # get Connection instance
+        con = getattr(self, self.connection_id)
+        # call to get db object
+        db = con()
+        return db
+    
+    def executeZSQL(self, query, args=None, max_rows=None):
+        """execute query with args on the database and return all results as Result object."""
+        logging.debug("executeZSQL query=%s args=%s"%(query,args))
+        dbc = self.getDB()
+        res = dbc.query(query, max_rows=max_rows, query_data=args)
+        # return result set as Result object with Brains
+        return Results(res)
+
+
+    #
+    # Old way using cursor from DA
+    # 
+    
     def getCursor(self,autocommit=True):
         """returns fresh DB cursor"""
-        conn = getattr(self,"_v_database_connection",None)
+        conn = getattr(self,"_v_database_connection", None)
         if conn is None:
             # create a new connection object
             try:
                 if self.connection_id is None:
                     # try to take the first existing ID
-                    connids = SQLConnectionIDs(self)
+                    connids = self.getConnectionIDs()
                     if len(connids) > 0:
-                        connection_id = connids[0][0]
+                        connection_id = connids[0][1]
                         self.connection_id = connection_id
                         logging.debug("connection_id: %s"%repr(connection_id))
 
                 da = getattr(self, self.connection_id)
+                logging.debug('da=%s'%da)
                 da.connect('')
                 # we copy the DAs database connection
                 conn = da._v_database_connection
-                #conn._register() # register with the Zope transaction system
+                #conn._register() # register with the Zope transaction system(?)
                 self._v_database_connection = conn
+                
             except Exception, e:
                 raise IOError("No database connection! (%s)"%str(e))
         
         cursor = conn.getcursor()
         if autocommit:
-            # is there a better version to get to the connection?
+            # TODO: is there a better version to get to the connection?
             cursor.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
             
         return cursor
-    
+
     def getFieldNameMap(self,fields):
         """returns a dict mapping field names to row indexes"""
         map = {}
--- a/RestDbInterface.py	Mon Feb 14 11:11:34 2011 +0100
+++ b/RestDbInterface.py	Mon Feb 14 23:20:43 2011 +0100
@@ -11,69 +11,15 @@
 import re
 import json
 import time
-import psycopg2
-# make psycopg use unicode objects
-import psycopg2.extensions
-psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
-psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
 
 from zope.interface import implements
 from zope.publisher.interfaces import IPublishTraverse
 from ZPublisher.BaseRequest import DefaultPublishTraverse
 
-
-def unicodify(s,alternate='latin-1'):
-    """decode str (utf-8 or latin-1 representation) into unicode object"""
-    if not s:
-        return u""
-    if isinstance(s, str):
-        try:
-            return s.decode('utf-8')
-        except:
-            return s.decode(alternate)
-    else:
-        return s
-
-def utf8ify(s):
-    """encode unicode object or string into byte string in utf-8 representation.
-       assumes string objects to be utf-8"""
-    if not s:
-        return ""
-    if isinstance(s, str):
-        return s
-    else:
-        return s.encode('utf-8')
-
-def getTextFromNode(node):
-    """get the cdata content of a XML node"""
-    if node is None:
-        return ""
-    
-    if isinstance(node, list):
-        nodelist = node
-    else:
-        nodelist=node.childNodes
-
-    rc = ""
-    for node in nodelist:
-        if node.nodeType == node.TEXT_NODE:
-           rc = rc + node.data
-    return rc
-
-def sqlName(s,lc=True):
-    """returns restricted ASCII-only version of string"""
-    if s is None:
-        return ""
-    
-    # all else -> "_"
-    s = re.sub(r'[^A-Za-z0-9_]','_',s)
-    if lc:
-        return s.lower()
-    
-    return s
+from DBInterface import *
 
 
-class RestDbInterface(Folder):
+class RestDbInterface(DBInterface, Folder):
     """Object for RESTful database queries
     path schema: /db/{schema}/{table}/
     omitting table gives a list of schemas
@@ -81,7 +27,7 @@
     """
     implements(IPublishTraverse)
     
-    meta_type="RESTdb"
+    meta_type="RESTdb2"
     manage_options=Folder.manage_options+(
         {'label':'Config','action':'manage_editRestDbInterfaceForm'},
         )
@@ -134,69 +80,6 @@
         """returns a JSON formatted string from object"""
         return json.dumps(object)
 
-    def getCursor(self,autocommit=True):
-        """returns fresh DB cursor"""
-        conn = getattr(self,"_v_database_connection",None)
-        if conn is None:
-            # create a new connection object
-            try:
-                if self.connection_id is None:
-                    # try to take the first existing ID
-                    connids = SQLConnectionIDs(self)
-                    if len(connids) > 0:
-                        connection_id = connids[0][0]
-                        self.connection_id = connection_id
-                        logging.debug("connection_id: %s"%repr(connection_id))
-
-                da = getattr(self, self.connection_id)
-                da.connect('')
-                # we copy the DAs database connection
-                conn = da._v_database_connection
-                #conn._register() # register with the Zope transaction system
-                self._v_database_connection = conn
-            except Exception, e:
-                raise IOError("No database connection! (%s)"%str(e))
-        
-        cursor = conn.getcursor()
-        if autocommit:
-            # is there a better version to get to the connection?
-            cursor.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
-            
-        return cursor
-    
-    def getFieldNameMap(self,fields):
-        """returns a dict mapping field names to row indexes"""
-        map = {}
-        i = 0
-        for f in fields:
-            map[f[0]] = i
-            i += 1
-            
-        return map
-    
-    def executeSQL(self, query, args=None, hasResult=True, autocommit=True):
-        """execute query with args on database and return all results.
-        result format: {"fields":fields, "rows":data}"""
-        logging.debug("executeSQL query=%s args=%s"%(query,args))
-        cur = self.getCursor(autocommit=autocommit)
-        if args is not None:
-            # make sure args is a list
-            if isinstance(args,basestring):
-                args = (args,)
-                
-        cur.execute(query, args)
-        # description of returned fields 
-        fields = cur.description
-        if hasResult:
-            # get all data in an array
-            data = cur.fetchall()
-            cur.close()
-            #logging.debug("fields: %s"%repr(fields))
-            #logging.debug("rows: %s"%repr(data))
-            return {"fields":fields, "rows":data}
-        else:
-            cur.close()
-            return None
 
     def isAllowed(self,action,schema,table,user=None):
         """returns if the requested action on the table is allowed"""
@@ -240,7 +123,6 @@
         # continue traversing
         return self
 
-
     def index_html(self,REQUEST,RESPONSE):
         """index method"""
         # ReST path was stored in request
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ZDBInterfaceFolder.py	Mon Feb 14 23:20:43 2011 +0100
@@ -0,0 +1,65 @@
+'''
+Created on 14.2.2011
+
+@author: casties
+'''
+
+from OFS.Folder import Folder
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from AccessControl import getSecurityManager, Unauthorized
+import logging
+import re
+
+from DBInterface import *
+
+
+class ZDBInterfaceFolder(DBInterface, Folder):
+    """Folder for database queries
+    """
+    
+    meta_type="ZDBInterfaceFolder"
+    manage_options=Folder.manage_options+(
+        {'label':'Config','action':'manage_editZDBInterfaceFolderForm'},
+        )
+
+    # management templates
+    manage_editZDBInterfaceFolderForm=PageTemplateFile('zpt/editZDBInterfaceFolder',globals())
+
+    
+    def __init__(self, id, title, connection_id=None):
+        """init"""
+        self.id = id
+        self.title = title
+        # database connection id
+        self.connection_id = connection_id
+
+
+    
+    def manage_editZDBInterfaceFolder(self, title=None, connection_id=None,
+                     REQUEST=None):
+        """Change the object"""
+        if title is not None:
+            self.title = title
+            
+        if connection_id is not None:
+            self.connection_id = connection_id
+                
+        #checkPermission=getSecurityManager().checkPermission
+        REQUEST.RESPONSE.redirect('manage_main')
+
+
+manage_addZDBInterfaceFolderForm=PageTemplateFile('zpt/addZDBInterfaceFolder',globals())
+
+def manage_addZDBInterfaceFolder(self, id, title='', label='', description='',
+                     createPublic=0,
+                     createUserF=0,
+                     REQUEST=None):
+        """Add a new object with id *id*."""
+    
+        ob=ZDBInterfaceFolder(str(id),title)
+        self._setObject(id, ob)
+        
+        #checkPermission=getSecurityManager().checkPermission
+        REQUEST.RESPONSE.redirect('manage_main')
+
+        
--- a/__init__.py	Mon Feb 14 11:11:34 2011 +0100
+++ b/__init__.py	Mon Feb 14 23:20:43 2011 +0100
@@ -1,6 +1,7 @@
 
 import RestDbInterface
 import WritableRestDbInterface
+import ZDBInterfaceFolder
 
 def initialize(context):
 
@@ -19,3 +20,11 @@
           WritableRestDbInterface.manage_addWritableRestDbInterface
           )
         )
+
+    context.registerClass(
+         ZDBInterfaceFolder.ZDBInterfaceFolder,
+        constructors = (
+          ZDBInterfaceFolder.manage_addZDBInterfaceFolderForm,
+          ZDBInterfaceFolder.manage_addZDBInterfaceFolder
+          )
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addZDBInterfaceFolder.zpt	Mon Feb 14 23:20:43 2011 +0100
@@ -0,0 +1,9 @@
+  <div tal:replace="structure here/manage_page_header">Header</div>
+  <h2>Add a ZDB interface folder</h2>
+  <form method="post" action="manage_addZDBInterfaceFolder">
+    <p class="form-label">ID</p>
+        <p class="form-element"><input size="80" name="id"/></p>
+    <p class="form-label">Title</p>
+        <p class="form-element"><input size="80" name="title"/></p>
+     <p><input type="submit" value="Add" /></p>
+  </form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editRestDbInterface.zpt	Mon Feb 14 23:20:43 2011 +0100
@@ -0,0 +1,16 @@
+  <div tal:replace="structure here/manage_page_header">Header</div>
+  <h2>Edit a RESTdb</h2>
+  <form method="post" action="manage_editRestDbInterface">
+    <p class="form-label">Title</p>
+        <p class="form-element"><input size="80" name="title" tal:attributes="value here/title"/></p>
+    <p class="form-label">Connection ID</p>
+    <p>
+    <select name="connection_id">
+      <tal:block tal:repeat="id python:[i[0] for i in here.getConnectionIDs()]">
+        <option  tal:condition="python:getattr(here,'connection_id','')==id"  tal:attributes="value id" selected tal:content="id"/>
+        <option  tal:condition="not:python:getattr(here,'connection_id','')==id"  tal:attributes="value id" tal:content="id"/>
+      </tal:block>
+    </select>
+    </p>
+     <p><input type="submit" value="Change" /></p>
+  </form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editZDBInterfaceFolder.zpt	Mon Feb 14 23:20:43 2011 +0100
@@ -0,0 +1,17 @@
+  <div tal:replace="structure here/manage_page_header">Header</div>
+  <h2>Edit a ZDB interface folder</h2>
+  <form method="post" action="manage_editZDBInterfaceFolder">
+    <p class="form-label">Title</p>
+        <p class="form-element"><input size="80" name="title" tal:attributes="value here/title"/></p>
+    <p class="form-label">Connection ID</p>
+    <pre tal:content="python:repr(here.getConnectionIDs())"/>
+    <p>
+    <select name="connection_id">
+      <tal:block tal:repeat="id python:[i[0] for i in here.getConnectionIDs()]">
+        <option  tal:condition="python:getattr(here,'connection_id','')==id"  tal:attributes="value id" selected tal:content="id"/>
+        <option  tal:condition="not:python:getattr(here,'connection_id','')==id"  tal:attributes="value id" tal:content="id"/>
+      </tal:block>
+    </select>
+    </p>
+     <p><input type="submit" value="Change" /></p>
+  </form>