From 8483a9b9dffcd8d0226670b70c899d00eccd618d Mon Sep 17 00:00:00 2001
From: Renaud Le Gac <legac@cppm.in2p3.fr>
Date: Wed, 20 Mar 2013 17:37:36 +0100
Subject: [PATCH] Upgrade to run with alias tables.

---
 controllers/plugin_dbui.py      |  6 +++++-
 modules/plugin_dbui/__init__.py |  1 +
 modules/plugin_dbui/dbsvc.py    | 25 +++++++++++++++++++++----
 modules/plugin_dbui/helper.py   | 14 ++++++++++++++
 static/plugin_dbui/CHANGELOG    |  1 +
 5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/controllers/plugin_dbui.py b/controllers/plugin_dbui.py
index bb9e574c..240d54b2 100644
--- a/controllers/plugin_dbui.py
+++ b/controllers/plugin_dbui.py
@@ -110,8 +110,12 @@ def dbui_conf():
         di[action].append({'name': method, 'len': nargs})
   
     # the stores configuration (static, for each table,...)
+    # NOTE: the interface require a store for all tables including alias.
+    # The only way to extract them is to scan the attributes list of 
+    # the DAL since the method db.tables() or any variant return 
+    # tables but not the alias one
     storeCfgs = plugins.dbui.static_stores
-    for table in db:
+    for table in dbui.get_all_tables(db):
         cfg = dbui.to_jsonstore(table)
         storeCfgs[cfg['storeId']] = cfg 
     
diff --git a/modules/plugin_dbui/__init__.py b/modules/plugin_dbui/__init__.py
index e406624c..0a5ead8a 100755
--- a/modules/plugin_dbui/__init__.py
+++ b/modules/plugin_dbui/__init__.py
@@ -50,6 +50,7 @@ from storemodifier import AddStore, StoreModifier
 from helper import (as_list,
                     decode_field,
                     encode_field,
+                    get_all_tables,
                     get_create_id,
                     get_field_validators,
                     get_file_paths,
diff --git a/modules/plugin_dbui/dbsvc.py b/modules/plugin_dbui/dbsvc.py
index 59d43a4b..62d85757 100644
--- a/modules/plugin_dbui/dbsvc.py
+++ b/modules/plugin_dbui/dbsvc.py
@@ -10,6 +10,7 @@ from gluon.contrib import simplejson as json
 from gluon.storage import Storage
 from helper import (encode_field, 
                     decode_field,
+                    get_all_tables,
                     get_foreign_field,
                     is_foreign_field,
                     rows_serializer)
@@ -168,6 +169,7 @@ class DbSvc(BaseSvc):
     
     def _is_fields_values_valid(self, table, fields):
         """Helper method to check each field value against its validators.
+        
         Return an empty dictionary when everything is OK or a dictionary
         with fields failing check: {field1: error1, field2: error2,...}
         
@@ -176,6 +178,14 @@ class DbSvc(BaseSvc):
         db = self.environment['db']
         
         for (field, val) in fields.items():
+        
+            # NOTE: checks are not applied to foreign fields since 
+            # consistency is garanty by the interface via the use of
+            # combobox. This approach help when running with alias table
+            # since validation crashed in that case.
+            if is_foreign_field(db[table][field]):
+                continue
+
             errmsg = db[table][field].validate(val)[1]
             if errmsg:
                 di[encode_field(table, field)] = errmsg
@@ -183,12 +193,17 @@ class DbSvc(BaseSvc):
         return di
 
 
-    def _is_table_in_db(self, table):
+    def _is_table_in_db(self, tablename):
         """Helper method to check that a table exist in the database.
+        The method handles regular and alias tables.
+        
         Raise the  DbSvcException if not.
         
         """
-        if table not in self.environment['db'].tables:
+        db = self.environment['db']
+        tablenames =  [table._tablename for table in get_all_tables(db)]
+        
+        if tablename not in tablenames:
             raise DbSvcException(TABLE_NOT_IN_DB % table)
 
 
@@ -439,12 +454,14 @@ class DbSvc(BaseSvc):
             query = self._encode_query(arg['where'])
 
         # Count the number of record in the table --require for the paging
+        # NOTE: the usual method db(db.table).count() failed with alias table
+        # it is why we use a more complicated approach.
         if query:
-            nrecords = db(query).count()
+            nrecords = len(db(query).select())
             
         else:
             table = arg['tableName']
-            nrecords = db(db[table].id).count()
+            nrecords = db(db[table]).count()
         
         # handle paging options (see Ext.PagingToolbar)
         kwargs = {}
diff --git a/modules/plugin_dbui/helper.py b/modules/plugin_dbui/helper.py
index 47f4d2a2..27ba60f5 100644
--- a/modules/plugin_dbui/helper.py
+++ b/modules/plugin_dbui/helper.py
@@ -8,6 +8,7 @@ import subprocess
 import tempfile
 
 from gluon import current
+from gluon.dal import Table
 from gluon.http import HTTP
 from gluon.validators import (IS_DATE_IN_RANGE,
                               IS_DATETIME_IN_RANGE,
@@ -65,6 +66,19 @@ def encode_field(*args):
     return ''.join([el[0].upper()+el[1:].lower() for el in args if len(el)])
 
 
+def get_all_tables(dal):
+    """Helper function to return a list of all gluon.dal.Table
+    house by the DAL object. The list includes alias table.
+    
+    It is recommend to use standard iterator provided by 
+    the DAL object. However by contruction, they ignore 
+    alias table.
+    
+    """
+    li = [dal[attr] for attr in dir(dal) if isinstance(dal[attr], Table)]
+    return li
+
+    
 def get_create_id(table, **kwargs):
     """Helper function to find the id of a row identified by 
     a set of field value pairs.
diff --git a/static/plugin_dbui/CHANGELOG b/static/plugin_dbui/CHANGELOG
index 05348e5a..0beb3aad 100644
--- a/static/plugin_dbui/CHANGELOG
+++ b/static/plugin_dbui/CHANGELOG
@@ -1,6 +1,7 @@
 --------------------------------- CHANGE LOG ----------------------------------
 
 HEAD
+  - Upgrade to run with alias table.
 
 0.4.10.3 (Mar 2013)
   - Fix a bug in App.BasePanelWithSelector for IE.
-- 
GitLab