Commit a362b437 authored by Vincent Pelletier's avatar Vincent Pelletier Committed by Eteri

all: Drop {as,build}SQL*Expression methods

To generate (and execute) SQL, use catalog tool.
parent f3536db8
...@@ -671,33 +671,6 @@ class Category(Folder): ...@@ -671,33 +671,6 @@ class Category(Folder):
""" """
return context.isMemberOf(self.getCategoryName()) return context.isMemberOf(self.getCategoryName())
security.declareProtected( Permissions.AccessContentsInformation, 'asSQLExpression' )
def asSQLExpression(self, strict_membership=0, table='category', base_category = None):
"""
A Predicate can be rendered as an sql expression. This
can be useful to create reporting trees based on the
ZSQLCatalog
"""
if base_category is None:
base_category = self
elif type(base_category) is type('a'):
base_category = self.portal_categories[base_category]
if strict_membership:
sql_text = '(%s.category_uid = %s AND %s.base_category_uid = %s ' \
'AND %s.category_strict_membership = 1)' % \
(table, self.getUid(), table,
base_category.getBaseCategoryUid(), table)
else:
sql_text = '(%s.category_uid = %s AND %s.base_category_uid = %s)' % \
(table, self.getUid(), table, base_category.getBaseCategoryUid())
# Now useless since we precompute the mapping
#for o in self.objectValues():
# sql_text += ' OR %s' % o.asSQLExpression()
return sql_text
security.declareProtected( Permissions.AccessContentsInformation, 'asSqlExpression' )
asSqlExpression = asSQLExpression
# A Category's categories is self # A Category's categories is self
...@@ -817,25 +790,6 @@ class BaseCategory(Category): ...@@ -817,25 +790,6 @@ class BaseCategory(Category):
"""Determines if related values should be indexed on target documents""" """Determines if related values should be indexed on target documents"""
return self.related_locally_indexed return self.related_locally_indexed
security.declareProtected(Permissions.AccessContentsInformation, 'asSQLExpression')
def asSQLExpression(self, strict_membership=0, table='category', base_category=None):
"""
A Predicate can be rendered as an sql expression. This
can be useful to create reporting trees based on the
ZSQLCatalog
"""
if strict_membership:
sql_text = '(%s.category_uid = %s AND %s.base_category_uid = %s ' \
'AND %s.category_strict_membership = 1)' % \
(table, self.uid, table, self.uid, table)
else:
sql_text = '(%s.category_uid = %s AND %s.base_category_uid = %s)' % \
(table, self.uid, table, self.uid)
# Now useless since we precompute the mapping
#for o in self.objectValues():
# sql_text += ' OR %s' % o.asSQLExpression()
return sql_text
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getBaseCategoryId') 'getBaseCategoryId')
def getBaseCategoryId(self): def getBaseCategoryId(self):
......
...@@ -124,8 +124,5 @@ class ContributionPredicate(Predicate, XMLObject): ...@@ -124,8 +124,5 @@ class ContributionPredicate(Predicate, XMLObject):
result = result and self.getDestinationPortalType() result = result and self.getDestinationPortalType()
return result return result
def asSQLExpression(self):
raise NotImplementedError, 'ContributionPredicate does not support asSQLExpression.'
def asQuery(self, *args, **kw): def asQuery(self, *args, **kw):
raise NotImplementedError('ContributionPredicate does not support asQuery.') raise NotImplementedError('ContributionPredicate does not support asQuery.')
...@@ -57,18 +57,6 @@ class IPredicate(Interface): ...@@ -57,18 +57,6 @@ class IPredicate(Interface):
(XXX-JPS - is this really needed ? is this appropriate (XXX-JPS - is this really needed ? is this appropriate
naming - probably not) naming - probably not)
""" """
def asSQLExpression():
"""
A Predicate can be rendered as an sql expression. This
can be useful to create reporting trees based on the
ZSQLCatalog. This SQL expression is however partial since
python scripts which are used by the test method of the predicate
can be converted to SQL. If a python script is defined to
implement test, results obtained through asSQLExpression
must be additionnaly tested by invoking test().
"""
def asQuery(): def asQuery():
""" """
A Predicate can be rendered as a set of catalog conditions. This A Predicate can be rendered as a set of catalog conditions. This
......
...@@ -384,41 +384,10 @@ allow_class(Selection) ...@@ -384,41 +384,10 @@ allow_class(Selection)
class DomainSelection(Acquisition.Implicit, Traversable, Persistent): class DomainSelection(Acquisition.Implicit, Traversable, Persistent):
""" """
A class to store a selection of domains which defines a report A class to store a selection of domains which defines a report
section. There are different ways to use DomainSelection in section.
SQL methods. As a general principle, SQL methods are passed
DomainSelection instances as a parameter.
Example 1: (hand coded) Do not use this class directly, but use selection_{domain,report}
parameters in SQLCatalog API.
The domain is accessed directly from the selection and a list of
uids is gathered from the ZODB to feed the SQL request. This
approach is only suitable for categories and relations. It is
not suitable for predicates. Do not use it unless there is no other way.
<dtml-if selection.domain.eip>
<dtml-in "selection.domain.eip.getCategoryChildUidList()">uid = <dtml-sqlvar sequence-item type="int"></dtml-in>
</dtml-if>
Example 2: (auto generated)
The domain object is in charge of generating automatically all
SQL expressions to feed the SQL method (or the catalog). This
is the recommended approach.
<dtml-var "selection.domain.asSQLExpression(table_map=(('eip','movement'), ('group', 'catalog')))">
<dtml-var "selection.domain.asSQLJoinExpression(table_map=(('eip','movement'), ('group', 'catalog')))">
Example 3: (mixed)
The category or predicate of the domain object is accessed. SQL
code generation is invoked on it. This is better than the manual
approach.
<dtml-var "selection.domain.eip.asSQLExpresion(table="resource_category")">
Current implementation is only suitable for categories.
It needs to be extended to support also predicates. The right approach
would be to turn any category into a predicate.
""" """
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -463,73 +432,6 @@ class DomainSelection(Acquisition.Implicit, Traversable, Persistent): ...@@ -463,73 +432,6 @@ class DomainSelection(Acquisition.Implicit, Traversable, Persistent):
return obj return obj
security.declarePublic('asSQLExpression')
def asSQLExpression(self, table_map=None, domain_id=None,
exclude_domain_id=None, strict_membership=0,
join_table="catalog", join_column="uid",
base_category=None, category_table_alias='category'):
select_expression = []
portal = self.getPortalObject()
for k, d in self.domain_dict.iteritems():
d = self._getDomainObject(portal, d)
if k == 'parent':
# Special treatment for parent
select_expression.append(
d.getParentSQLExpression(table='catalog',
strict_membership=strict_membership))
elif k is not None:
if getattr(aq_base(d), 'isPredicate', 0):
select_expression.append(
d.asSQLExpression(table='%s_%s' % (k, category_table_alias),
strict_membership=strict_membership))
else:
# This is a category, we must join
select_expression.append('%s.%s = %s_%s.uid' % \
(join_table, join_column,
k, category_table_alias))
select_expression.append(
d.asSQLExpression(table='%s_%s' % (k, category_table_alias),
base_category=k,
strict_membership=strict_membership))
# XXX We should take into account k explicitely
# if we want to support category acquisition
if select_expression:
result = "( %s )" % ' AND '.join(select_expression)
else:
result = ''
#LOG('DomainSelection', 0, 'asSQLExpression returns %r' % (result,))
return result
# Compatibility SQL Sql
security.declarePublic('asSqlExpression')
asSqlExpression = asSQLExpression
security.declarePublic('asSQLJoinExpression')
def asSQLJoinExpression(self, domain_id=None, exclude_domain_id=None,
category_table_alias='category'):
join_expression = []
#LOG('DomainSelection', 0, 'domain_id = %r, exclude_domain_id = %r, self.domain_dict = %r' % (domain_id, exclude_domain_id, self.domain_dict))
portal = self.getPortalObject()
for k, d in self.domain_dict.iteritems():
d = self._getDomainObject(portal, d)
if k == 'parent':
pass
elif k is not None:
if getattr(aq_base(d), 'isPredicate', 0):
join_expression.append(d.asSQLJoinExpression(table='%s_%s' % (k, category_table_alias)))
else:
# This is a category, we must join
join_expression.append('category AS %s_%s' % (k, category_table_alias))
result = "%s" % ' , '.join(join_expression)
#LOG('DomainSelection', 0, 'asSQLJoinExpression returns %r' % (result,))
return result
# Compatibility SQL Sql
security.declarePublic('asSqlJoinExpression')
asSqlJoinExpression = asSQLJoinExpression
security.declarePublic('asDomainDict') security.declarePublic('asDomainDict')
def asDomainDict(self, domain_id=None, exclude_domain_id=None): def asDomainDict(self, domain_id=None, exclude_domain_id=None):
return self.domain_dict return self.domain_dict
......
...@@ -1365,42 +1365,6 @@ class SelectionTool( BaseTool, SimpleItem ): ...@@ -1365,42 +1365,6 @@ class SelectionTool( BaseTool, SimpleItem ):
return ComplexQuery(query_list) return ComplexQuery(query_list)
return SimpleQuery(uid=0, comparison_operator='>') return SimpleQuery(uid=0, comparison_operator='>')
security.declarePublic('buildSQLJoinExpressionFromDomainSelection')
def buildSQLJoinExpressionFromDomainSelection(self, selection_domain,
domain_id=None,
exclude_domain_id=None,
category_table_alias='category'):
if isinstance(selection_domain, DomainSelection):
warnings.warn("To pass a DomainSelection instance is deprecated.\n"
"Please use a domain dict instead.",
DeprecationWarning)
else:
selection_domain = DomainSelection(selection_domain).__of__(self)
return selection_domain.asSQLJoinExpression(
category_table_alias=category_table_alias)
security.declarePublic('buildSQLExpressionFromDomainSelection')
def buildSQLExpressionFromDomainSelection(self, selection_domain,
table_map=None, domain_id=None,
exclude_domain_id=None,
strict_membership=0,
join_table="catalog",
join_column="uid",
base_category=None,
category_table_alias='category'):
if isinstance(selection_domain, DomainSelection):
warnings.warn("To pass a DomainSelection instance is deprecated.\n"
"Please use a domain dict instead.",
DeprecationWarning)
else:
selection_domain = DomainSelection(selection_domain).__of__(self)
return selection_domain.asSQLExpression(
strict_membership = strict_membership,
join_table=join_table,
join_column=join_column,
base_category=base_category,
category_table_alias = category_table_alias)
def _aq_dynamic(self, name): def _aq_dynamic(self, name):
""" """
Generate viewSearchRelatedDocumentDialog0, Generate viewSearchRelatedDocumentDialog0,
......
...@@ -179,31 +179,6 @@ class TestSelectionTool(ERP5TypeTestCase): ...@@ -179,31 +179,6 @@ class TestSelectionTool(ERP5TypeTestCase):
def testPage(self): def testPage(self):
raise NotImplementedError('test should be added') raise NotImplementedError('test should be added')
def testDomainSelection(self):
self.assertEqual('',
self.portal_selections.buildSQLJoinExpressionFromDomainSelection({}))
self.assertEqual('',
self.portal_selections.buildSQLExpressionFromDomainSelection({}))
from Products.ERP5Form.Selection import DomainSelection
self.assertEqual('',
self.portal_selections.buildSQLJoinExpressionFromDomainSelection(DomainSelection({}).__of__(self.portal_selections)))
category_tool = self.getCategoryTool()
base = category_tool.newContent(portal_type = 'Base Category',
id='test_base_cat')
base_uid = base.getUid()
self.assertEqual('category AS test_base_cat_category',
self.portal_selections.buildSQLJoinExpressionFromDomainSelection({'test_base_cat': ('portal_categories', 'test_base_cat')}))
self.assertEqual('( catalog.uid = test_base_cat_category.uid AND (test_base_cat_category.category_uid = %d AND test_base_cat_category.base_category_uid = %d) )' % (base_uid, base_uid),
self.portal_selections.buildSQLExpressionFromDomainSelection({'test_base_cat': ('portal_categories', 'test_base_cat')}))
test = base.newContent(portal_type = 'Category', id = 'test_cat')
test_uid = test.getUid()
self.assertEqual('category AS test_base_cat_category',
self.portal_selections.buildSQLJoinExpressionFromDomainSelection({'test_base_cat': ('portal_categories', 'test_base_cat/test_cat')}))
self.assertEqual('( catalog.uid = test_base_cat_category.uid AND (test_base_cat_category.category_uid = %d AND test_base_cat_category.base_category_uid = %d) )' % (test_uid, base_uid),
self.portal_selections.buildSQLExpressionFromDomainSelection({'test_base_cat': ('portal_categories', 'test_base_cat/test_cat')}))
self.assertEqual('( catalog.uid = test_base_cat_category.uid AND (test_base_cat_category.category_uid = %d AND test_base_cat_category.base_category_uid = %d AND test_base_cat_category.category_strict_membership = 1) )' % (test_uid, base_uid),
self.portal_selections.buildSQLExpressionFromDomainSelection({'test_base_cat': ('portal_categories', 'test_base_cat/test_cat')}, strict_membership = 1))
def testDict(self): def testDict(self):
self.assertEqual({}, self.assertEqual({},
self.portal_selections.getSelectionDomainDictFor('test_selection')) self.portal_selections.getSelectionDomainDictFor('test_selection'))
......
...@@ -1591,36 +1591,6 @@ class Base( CopyContainer, ...@@ -1591,36 +1591,6 @@ class Base( CopyContainer,
assert mount_point._getMountedConnection(connection) is connection assert mount_point._getMountedConnection(connection) is connection
return mount_point._traverseToMountedRoot(connection.root(), None) return mount_point._traverseToMountedRoot(connection.root(), None)
security.declareProtected(Permissions.AccessContentsInformation,
'asSQLExpression')
def asSQLExpression(self, strict_membership=0, table='category', base_category = None):
"""
Any document can be used as a Category. It can therefore
serve in a Predicate and must be rendered as an sql expression. This
can be useful to create reporting trees based on the
ZSQLCatalog whenever documents are used rather than categories
TODO:
- strict_membership is not implemented
"""
if isinstance(base_category, str):
base_category = self.portal_categories[base_category]
if base_category is None:
sql_text = '(%s.category_uid = %s)' % \
(table, self.getUid())
else:
sql_text = '(%s.category_uid = %s AND %s.base_category_uid = %s)' % \
(table, self.getUid(), table, base_category.getBaseCategoryUid())
return sql_text
security.declareProtected( Permissions.AccessContentsInformation,
'getParentSQLExpression' )
def getParentSQLExpression(self, table = 'catalog', strict_membership = 0):
"""
Builds an SQL expression to search children and subclidren
"""
return "%s.parent_uid = %s" % (table, self.getUid())
security.declareProtected( Permissions.AccessContentsInformation, security.declareProtected( Permissions.AccessContentsInformation,
'getParentUid' ) 'getParentUid' )
def getParentUid(self): def getParentUid(self):
......
...@@ -1492,25 +1492,6 @@ class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn): ...@@ -1492,25 +1492,6 @@ class Folder(CopyContainer, CMFBTreeFolder, CMFHBTreeFolder, Base, FolderMixIn):
return self.objectIds(*args, **kw) return self.objectIds(*args, **kw)
# Overloading # Overloading
security.declareProtected(Permissions.AccessContentsInformation,
'getParentSQLExpression')
def getParentSQLExpression(self, table='catalog', strict_membership=0):
"""
Builds an SQL expression to search children and subchildren
"""
if strict_membership:
return Base.getParentSQLExpression(self,
table=table,
strict_membership=strict_membership)
result = "%s.parent_uid = %s" % (table, self.getUid())
for o in self.objectValues():
if hasattr(aq_base(o), 'objectValues'):
# Do not consider non folder objects
result = "%s OR %s" % ( result,
o.getParentSQLExpression(table=table,
strict_membership=strict_membership))
return "( %s )" % result
security.declareProtected( Permissions.AccessContentsInformation, security.declareProtected( Permissions.AccessContentsInformation,
'objectValues' ) 'objectValues' )
def objectValues(self, spec=None, meta_type=None, portal_type=None, def objectValues(self, spec=None, meta_type=None, portal_type=None,
......
...@@ -41,7 +41,7 @@ from Products.ERP5Type.XMLObject import XMLObject ...@@ -41,7 +41,7 @@ from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Utils import convertToUpperCase from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.Cache import readOnlyTransactionCache from Products.ERP5Type.Cache import readOnlyTransactionCache
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
from Products.ZSQLCatalog.SQLCatalog import SQLQuery, SimpleQuery, ComplexQuery from Products.ZSQLCatalog.SQLCatalog import SimpleQuery, ComplexQuery
from Products.ERP5Type.Globals import PersistentMapping from Products.ERP5Type.Globals import PersistentMapping
from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
from Products.CMFCore.Expression import Expression from Products.CMFCore.Expression import Expression
...@@ -199,156 +199,6 @@ class Predicate(XMLObject): ...@@ -199,156 +199,6 @@ class Predicate(XMLObject):
result = expression(createExpressionContext(context)) result = expression(createExpressionContext(context))
return result return result
security.declareProtected( Permissions.AccessContentsInformation,
'buildSQLQuery' )
def buildSQLQuery(self, strict_membership=0, table='category',
join_table='catalog', join_column='uid',
**kw):
"""
A Predicate can be rendered as an SQL expression. This
can be used to generate SQL requests in reports or in
catalog search queries.
XXX - This method is not implemented yet
"""
# Build the identity criterion
catalog_kw = {}
catalog_kw.update(kw) # query_table, REQUEST, ignore_empty_string, **kw
criterion_list = self.getCriterionList()
if criterion_list:
for criterion in criterion_list:
p = criterion.property
if criterion.min:
if criterion.max:
catalog_kw[p] = {'query': (criterion.min, criterion.max),
'range': 'minmax'}
else:
catalog_kw[p] = {'query': criterion.min, 'range': 'min'}
elif criterion.max:
catalog_kw[p] = {'query': criterion.max, 'range': 'max'}
else:
# if a filter was passed as argument
try:
f = catalog_kw[p]
except KeyError:
catalog_kw[p] = criterion.identity
else:
f = set(f) if isinstance(f, (tuple, list)) else {f}
i = criterion.identity
if isinstance(i, (tuple, list)):
f.intersection_update(i)
else:
f = (i,) if i in f else ()
catalog_kw[p] = list(f)
portal = self.getPortalObject()
resolveCategory = portal.portal_categories._resolveCategory
from_table_dict = {}
# First build SQL for membership criteria
# It would be much nicer if all this was handled by the catalog in a central place
membership_dict = {}
for base_category in self.getMembershipCriterionBaseCategoryList():
membership_dict[base_category] = [] # Init dict with valid base categories
for category in self.getMembershipCriterionCategoryList():
base_category = category.split('/')[0] # Retrieve base category
if membership_dict.has_key(base_category):
category_value = resolveCategory(category)
if category_value is not None:
table_alias = "single_%s_%s" % (table, base_category)
from_table_dict[table_alias] = 'category'
membership_dict[base_category].append(category_value.asSQLExpression(
strict_membership=strict_membership,
table=table_alias,
base_category=base_category))
membership_select_list = []
for expression_list in membership_dict.values():
or_expression = ' OR '.join(expression_list)
if or_expression:
membership_select_list.append('( %s )' % or_expression)
# Then build SQL for multimembership_dict criteria
multimembership_dict = {}
for base_category in self.getMultimembershipCriterionBaseCategoryList():
multimembership_dict[base_category] = [] # Init dict with valid base categories
join_count = 0
for category in self.getMembershipCriterionCategoryList():
base_category = category.split('/')[0] # Retrieve base category
if multimembership_dict.has_key(base_category):
category_value = resolveCategory(category)
if category_value is not None:
join_count += 1
table_alias = "multi_%s_%s" % (table, join_count)
from_table_dict[table_alias] = 'category'
multimembership_dict[base_category].append(category_value.asSQLExpression(
strict_membership=strict_membership,
table=table_alias,
base_category=base_category))
multimembership_select_list = []
for expression_list in multimembership_dict.values():
and_expression = ' AND '.join(expression_list)
if and_expression:
multimembership_select_list.append(and_expression)
# BBB: accessor is not present on old Predicate property sheet.
if not getattr(self, 'isEmptyCriterionValid', lambda: True)() and \
not catalog_kw and not membership_select_list and not multimembership_select_list:
# By catalog definition, no object has uid 0, so this condition forces an
# empty result.
catalog_kw['uid'] = 0
# Build the join where expression
join_select_list = []
for k in from_table_dict.iterkeys():
join_select_list.append('%s.%s = %s.uid' % (join_table, join_column, k))
sql_text = ' AND '.join(join_select_list + membership_select_list +
multimembership_select_list)
# Now merge identity and membership criteria
if len(sql_text):
catalog_kw['where_expression'] = SQLQuery(sql_text)
# force implicit join
catalog_kw['implicit_join'] = True
sql_query = portal.portal_catalog.buildSQLQuery(**catalog_kw)
# XXX from_table_list is None most of the time after the explicit_join work
for alias, table in sql_query['from_table_list']:
if from_table_dict.has_key(alias):
raise KeyError, "The same table is used twice for an identity criterion and for a membership criterion"
from_table_dict[alias] = table
sql_query['from_table_list'] = from_table_dict.items()
return sql_query
# Compatibililty SQL Sql
security.declareProtected( Permissions.AccessContentsInformation, 'buildSqlQuery' )
buildSqlQuery = buildSQLQuery
security.declareProtected( Permissions.AccessContentsInformation, 'asSQLExpression' )
def asSQLExpression(self, strict_membership=0, table='category'):
"""
A Predicate can be rendered as an SQL expression. This
can be used to generate SQL requests in reports or in
catalog search queries.
"""
return self.buildSQLQuery(strict_membership=strict_membership, table=table)['where_expression']
# Compatibililty SQL Sql
security.declareProtected( Permissions.AccessContentsInformation, 'asSqlExpression' )
asSqlExpression = asSQLExpression
security.declareProtected( Permissions.AccessContentsInformation, 'asSQLJoinExpression' )
def asSQLJoinExpression(self, strict_membership=0, table='category', join_table='catalog', join_column='uid'):
"""
"""
table_list = self.buildSQLQuery(strict_membership=strict_membership, table=table)['from_table_list']
sql_text_list = map(lambda (a,b): '%s AS %s' % (b,a), filter(lambda (a,b): a != join_table, table_list))
return ' , '.join(sql_text_list)
# Compatibililty SQL Sql
security.declareProtected( Permissions.AccessContentsInformation, 'asSqlJoinExpression' )
asSqlJoinExpression = asSQLJoinExpression
security.declareProtected(Permissions.AccessContentsInformation, 'asQuery') security.declareProtected(Permissions.AccessContentsInformation, 'asQuery')
def asQuery(self, strict_membership=False): def asQuery(self, strict_membership=False):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment